pax_global_header00006660000000000000000000000064147622666060014531gustar00rootroot0000000000000052 comment=06bb511db1256eec27501f686c5ec17cbde76af4 dtkcore-5.7.12/000077500000000000000000000000001476226660600132605ustar00rootroot00000000000000dtkcore-5.7.12/.clang-format000066400000000000000000000164501476226660600156410ustar00rootroot00000000000000--- # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto Language: Cpp # BasedOnStyle: LLVM # 访问说明符(public、private等)的偏移 AccessModifierOffset: -4 # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) AlignAfterOpenBracket: Align # 连续赋值时,对齐所有等号 AlignConsecutiveAssignments: None # 连续声明时,对齐所有声明的变量名 AlignConsecutiveDeclarations: None AlignEscapedNewlines: Right # 左对齐逃脱换行(使用反斜杠换行)的反斜杠 #AlignEscapedNewlinesLeft: true # 水平对齐二元和三元表达式的操作数 AlignOperands: true # 对齐连续的尾随的注释 AlignTrailingComments: true # 允许函数声明的所有参数在放在下一行 AllowAllParametersOfDeclarationOnNextLine: true # 允许短的块放在同一行 AllowShortBlocksOnASingleLine: Empty # 允许短的case标签放在同一行 AllowShortCaseLabelsOnASingleLine: false # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All AllowShortFunctionsOnASingleLine: Inline # 允许短的if语句保持在同一行 AllowShortIfStatementsOnASingleLine: false # 允许短的循环保持在同一行 AllowShortLoopsOnASingleLine: false # 总是在定义返回类型后换行(deprecated) AlwaysBreakAfterDefinitionReturnType: None # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) AlwaysBreakAfterReturnType: None # 总是在多行string字面量前换行 AlwaysBreakBeforeMultilineStrings: false # 总是在template声明后换行 AlwaysBreakTemplateDeclarations: Yes # false表示函数实参要么都在同一行,要么都各自一行 BinPackArguments: false # false表示所有形参要么都在同一行,要么都各自一行 BinPackParameters: false # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 BraceWrapping: # class定义后面 AfterClass: true # 控制语句后面 AfterControlStatement: Never # enum定义后面 AfterEnum: false # 函数定义后面 AfterFunction: true # 命名空间定义后面 AfterNamespace: false # ObjC定义后面 AfterObjCDeclaration: false # struct定义后面 AfterStruct: true # union定义后面 AfterUnion: true AfterExternBlock: false # catch之前 BeforeCatch: false # else之前 BeforeElse: false # 缩进大括号 IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) BreakBeforeBinaryOperators: None # 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), # Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), # Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom # 注:这里认为语句块也属于函数 BreakBeforeBraces: Custom # 在三元运算符前换行 BreakBeforeTernaryOperators: false # 在构造函数的初始化列表的逗号前换行 BreakConstructorInitializersBeforeComma: true BreakConstructorInitializers: BeforeColon # 每行字符的限制,0表示没有限制 ColumnLimit: 130 # 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false # 构造函数的初始化列表要么都在同一行,要么都各自一行 ConstructorInitializerAllOnOneLineOrOnePerLine: false # 构造函数的初始化列表的缩进宽度 ConstructorInitializerIndentWidth: 4 # 延续的行的缩进宽度 ContinuationIndentWidth: 4 # 去除C++11的列表初始化的大括号{后和}前的空格 Cpp11BracedListStyle: true # 继承最常用的指针和引用的对齐方式 DerivePointerAlignment: false # 关闭格式化 DisableFormat: false # 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) ExperimentalAutoDetectBinPacking: false # 需要被解读为foreach循环而不是函数调用的宏 ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] # 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), # 可以定义负数优先级从而保证某些#include永远在最前面 IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 - Regex: '^(<|"(gtest|isl|json)/)' Priority: 3 - Regex: '.*' Priority: 1 # 缩进case标签 IndentCaseLabels: true #IndentPPDirectives: AfterHash # 缩进宽度 IndentWidth: 4 # 函数返回类型换行时,缩进函数声明或函数定义的函数名 IndentWrappedFunctionNames: false # 保留在块开始处的空行 KeepEmptyLinesAtTheStartOfBlocks: false # 开始一个块的宏的正则表达式 MacroBlockBegin: '' # 结束一个块的宏的正则表达式 MacroBlockEnd: '' # 连续空行的最大数量 MaxEmptyLinesToKeep: 1 # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All NamespaceIndentation: Inner # 使用ObjC块时缩进宽度 ObjCBlockIndentWidth: 4 # 在ObjC的@property后添加一个空格 ObjCSpaceAfterProperty: false # 在ObjC的protocol列表前添加一个空格 ObjCSpaceBeforeProtocolList: true # 在call(后对函数调用换行的penalty PenaltyBreakBeforeFirstCallParameter: 19 # 在一个注释中引入换行的penalty PenaltyBreakComment: 300 # 第一次在<<前换行的penalty PenaltyBreakFirstLessLess: 120 # 在一个字符串字面量中引入换行的penalty PenaltyBreakString: 1000 # 对于每个在行字符数限制之外的字符的penalty PenaltyExcessCharacter: 1000000 # 将函数的返回类型放到它自己的行的penalty PenaltyReturnTypeOnItsOwnLine: 60 # 指针和引用的对齐: Left, Right, Middle PointerAlignment: Right # 允许重新排版注释 ReflowComments: true # 允许排序#include SortIncludes: Never # 在C风格类型转换后添加空格 SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true # 在赋值运算符之前添加空格 SpaceBeforeAssignmentOperators: true # 开圆括号之前添加一个空格: Never, ControlStatements, Always SpaceBeforeParens: ControlStatements # 在空的圆括号中添加空格 SpaceInEmptyParentheses: false # 在尾随的评论前添加的空格数(只适用于//) SpacesBeforeTrailingComments: 2 # 在尖括号的<后和>前添加空格 SpacesInAngles: false # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 SpacesInContainerLiterals: false # 在C风格类型转换的括号中添加空格 SpacesInCStyleCastParentheses: false # 在圆括号的(后和)前添加空格 SpacesInParentheses: false # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 SpacesInSquareBrackets: false # 标准: Cpp03, Cpp11, Auto Standard: Auto # tab宽度 TabWidth: 4 # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always UseTab: Never dtkcore-5.7.12/.clog.toml000066400000000000000000000001601476226660600151540ustar00rootroot00000000000000[clog] repository = "https://github.com/linuxdeepin/dtkcore" from-latest-tag = true changelog = "CHANGELOG.md" dtkcore-5.7.12/.github/000077500000000000000000000000001476226660600146205ustar00rootroot00000000000000dtkcore-5.7.12/.github/ISSUE_TEMPLATE/000077500000000000000000000000001476226660600170035ustar00rootroot00000000000000dtkcore-5.7.12/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000023651476226660600210010ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: BUG Report | 缺陷报告 url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=bug-report.yml about: Please create bug reports to the issue board in our dtk repo. - name: docs-update | 文档补充 url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=docs-update.yml about: Please create docs-update to the issue board in our dtk repo. - name: unit-test-report | 单元测试报告 url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=unit-test-report.yml about: Please create unit-test-report to the issue board in our dtk repo. - name: Feature Request | 特性请求 url: https://github.com/linuxdeepin/developer-center/discussions/new?category=features-request-ideas-%E7%89%B9%E6%80%A7%E8%AF%B7%E6%B1%82-%E5%A4%B4%E8%84%91%E9%A3%8E%E6%9A%B4 about: Please create feature requests to the discussion board in our developer-center repo. - name: General Discussion & Questions | 常规讨论与问答 url: https://github.com/linuxdeepin/developer-center/discussions/categories/q-a-%E9%97%AE%E7%AD%94%E6%9D%BF%E5%9D%97 about: Please use the discussion board in our developer-center repo. dtkcore-5.7.12/.github/ISSUE_TEMPLATE/document.md000066400000000000000000000005241476226660600211440ustar00rootroot00000000000000--- name: Docs update about: Document Normalization title: 'Doc: [Document Type][file name]' labels: 'Doc' assignees: '' --- ## Target files (目标文件) ## Planned completion time (计划完成时间) ## Document Type (文档类型) [] New documents [] Standardized documents [] Internationalization of documents [] Example documents dtkcore-5.7.12/.github/workflows/000077500000000000000000000000001476226660600166555ustar00rootroot00000000000000dtkcore-5.7.12/.github/workflows/backup-to-gitlab.yml000066400000000000000000000005371476226660600225320ustar00rootroot00000000000000name: backup to gitlab on: [push] concurrency: group: ${{ github.workflow }} cancel-in-progress: true jobs: backup-to-gitlabwh: uses: linuxdeepin/.github/.github/workflows/backup-to-gitlabwh.yml@master secrets: inherit backup-to-gitee: uses: linuxdeepin/.github/.github/workflows/backup-to-gitee.yml@master secrets: inherit dtkcore-5.7.12/.github/workflows/call-auto-tag.yml000066400000000000000000000005171476226660600220350ustar00rootroot00000000000000name: auto tag on: pull_request_target: types: [opened, synchronize, closed] paths: - "debian/changelog" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: auto_tag: uses: linuxdeepin/.github/.github/workflows/auto-tag.yml@master secrets: inherit dtkcore-5.7.12/.github/workflows/call-build-distribution.yml000066400000000000000000000004321476226660600241240ustar00rootroot00000000000000name: Call build-distribution on: push: paths-ignore: - ".github/workflows/**" pull_request_target: paths-ignore: - ".github/workflows/**" jobs: check_job: uses: linuxdeepin/.github/.github/workflows/build-distribution.yml@master secrets: inherit dtkcore-5.7.12/.github/workflows/call-chatOps.yml000066400000000000000000000002421476226660600217100ustar00rootroot00000000000000name: chatOps on: issue_comment: types: [created] jobs: chatopt: uses: linuxdeepin/.github/.github/workflows/chatOps.yml@master secrets: inherit dtkcore-5.7.12/.github/workflows/call-clacheck.yml000066400000000000000000000005251476226660600220500ustar00rootroot00000000000000name: Call CLA check on: issue_comment: types: [created] pull_request_target: types: [opened, closed, synchronize] concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: clacheck: uses: linuxdeepin/.github/.github/workflows/cla-check.yml@master secrets: inherit dtkcore-5.7.12/.github/workflows/call-commitlint.yml000066400000000000000000000003641476226660600224730ustar00rootroot00000000000000name: Call commitlint on: pull_request_target: concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: check_job: uses: linuxdeepin/.github/.github/workflows/commitlint.yml@master dtkcore-5.7.12/.github/workflows/call-deploy-dev-doc.yml000066400000000000000000000007401476226660600231250ustar00rootroot00000000000000name: deploy docs on: push: branches: ["master"] workflow_dispatch: inputs: tag: required: true type: string permissions: contents: read pages: write id-token: write # Allow one concurrent deployment concurrency: group: "pages" cancel-in-progress: true jobs: deploydocs: uses: linuxdeepin/.github/.github/workflows/deploy-dev-doc.yml@master with: ref: ${{ inputs.tag }} secrets: inherit dtkcore-5.7.12/.github/workflows/call-doc-check.yml000066400000000000000000000004671476226660600221400ustar00rootroot00000000000000name: doxygen-check on: pull_request_target: paths-ignore: - ".github/workflows/**" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: check_job: uses: linuxdeepin/.github/.github/workflows/doc-check.yml@master secrets: inherit dtkcore-5.7.12/.github/workflows/call-license-check.yml000066400000000000000000000005521476226660600230100ustar00rootroot00000000000000name: Call License and README Check on: pull_request_target: types: [opened, synchronize, reopened] permissions: pull-requests: write contents: read concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: license-check: uses: linuxdeepin/.github/.github/workflows/license-check.yml@master dtkcore-5.7.12/.github/workflows/call-synchronize-to-dtk6.yml000066400000000000000000000010311476226660600241450ustar00rootroot00000000000000name: Call synchronize to dtk6 on: pull_request_target: paths-ignore: - "debian/**" - "archlinux/**" - "rpm/**" - ".obs/**" - ".github/**" jobs: call-synchronize: uses: linuxdeepin/dtk/.github/workflows/synchronize-to-dtk6.yml@master secrets: inherit with: dest_repo: linuxdeepin/dtk6core source_repo: ${{ github.event.pull_request.head.repo.full_name }} source_ref: ${{ github.event.pull_request.head.ref }} pull_number: ${{ github.event.pull_request.number }} dtkcore-5.7.12/.github/workflows/cppcheck.yml000066400000000000000000000012651476226660600211640ustar00rootroot00000000000000name: cppcheck on: pull_request_target: paths-ignore: - ".github/workflows/**" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: cppchceck: name: cppcheck runs-on: ubuntu-latest steps: - run: export - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - uses: linuxdeepin/action-cppcheck@main with: github_token: ${{ secrets.GITHUB_TOKEN }} repository: ${{ github.repository }} pull_request_id: ${{ github.event.pull_request.number }} allow_approve: false dtkcore-5.7.12/.gitignore000066400000000000000000000005401476226660600152470ustar00rootroot00000000000000# Compiled Object files *.slo *.lo *.o # Compiled Dynamic libraries *.so *.dylib # Compiled Static libraries *.lai *.la *.a build*/ *.pro.user* *.DS_Store # executeable files *.qm src/DtkCores bin/ .qmake* Makefile cmake/DtkCore* .cache *.pc *.pri dtkcore_config.h *.user #tools .vscode .idea # Ignore Doxygen theme files docs/doxygen-theme/ dtkcore-5.7.12/.gitlab-ci.yml000066400000000000000000000002271476226660600157150ustar00rootroot00000000000000include: - remote: 'https://gitlab.deepin.io/dev-tools/letmeci/raw/master/gitlab-ci/dde.yml' variables: CPPCHECK: "true" CODESPELL: "true" dtkcore-5.7.12/.obs/000077500000000000000000000000001476226660600141215ustar00rootroot00000000000000dtkcore-5.7.12/.obs/workflows.yml000066400000000000000000000023121476226660600166770ustar00rootroot00000000000000test_build: steps: - link_package: source_project: deepin:Develop:dde source_package: %{SCM_REPOSITORY_NAME} target_project: deepin:CI - configure_repositories: project: deepin:CI repositories: - name: deepin_develop paths: - target_project: deepin:CI target_repository: deepin_develop architectures: - x86_64 - aarch64 - name: debian paths: - target_project: deepin:CI target_repository: debian_sid architectures: - x86_64 - name: archlinux paths: - target_project: deepin:CI target_repository: archlinux architectures: - x86_64 filters: event: pull_request tag_build: steps: - branch_package: source_project: deepin:Develop:dde source_package: %{SCM_REPOSITORY_NAME} target_project: deepin:Unstable:dde filters: event: tag_push commit_build: steps: - trigger_services: project: deepin:Develop:dde package: %{SCM_REPOSITORY_NAME} filters: event: push dtkcore-5.7.12/.packit.yaml000066400000000000000000000007241476226660600155000ustar00rootroot00000000000000# See the documentation for more information: # https://packit.dev/docs/configuration/ specfile_path: rpm/dtkcore.spec # add or remove files that should be synced synced_files: - rpm/dtkcore.spec - .packit.yaml upstream_package_name: dtkcore # downstream (Fedora) RPM package name downstream_package_name: dtkcore actions: fix-spec-file: | bash -c "sed -i -r \"0,/Version:/ s/Version:(\s*)\S*/Version:\1${PACKIT_PROJECT_VERSION}/\" rpm/dtkcore.spec" dtkcore-5.7.12/.project.json000066400000000000000000000002421476226660600156750ustar00rootroot00000000000000{ "Type": "homebrew", "3rdparty": ["tools/qdbusxml2cpp"], "ignore": ["src/translations","src/widgets/assets","doc",".tx"], "license": ["GPLv3"] } dtkcore-5.7.12/.release.json000066400000000000000000000010451476226660600156510ustar00rootroot00000000000000{ "commit": { "quilt": false, "pkgver": "echo $(git tag | sort -V | tail -n1)'+r'$(git log $(git describe --abbrev=0 --tags)..HEAD --oneline|wc -l)'+g'$(git rev-parse --short HEAD);", "dist": "experimental" }, "release": { "quilt": true, "pkgver": "git describe --abbrev=0 --tags %(ref)s", "dist": "unstable" }, "release-candidate": { "quilt": true, "dist": "unstable" } } dtkcore-5.7.12/.reuse/000077500000000000000000000000001476226660600144615ustar00rootroot00000000000000dtkcore-5.7.12/.reuse/dep5000066400000000000000000000031221476226660600152370ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: dtkcore Upstream-Contact: UnionTech Software Technology Co., Ltd. <> Source: https://github.com/linuxdeepin/dtkcore # Sample paragraph, commented out: # # Files: src/* # Copyright: $YEAR $NAME <$CONTACT> # License: ... # ci Files: .github/* *.yml *.yaml .obs/* .syncexclude Copyright: None License: CC0-1.0 # git Files: .gitignore Copyright: None License: CC0-1.0 # config Files: *.toml *.conf *.json .clang-format Copyright: None License: CC0-1.0 # qt Files: *.pro *.pri *.qrc *.prf Copyright: None License: CC0-1.0 # cmake Files: *.cmake *CMakeLists.txt *.pc.in Copyright: None License: CC0-1.0 # debian Files: debian/* Copyright: None License: CC0-1.0 # Arch Files: archlinux/* Copyright: None License: CC0-1.0 # rpm Files: rpm/* Copyright: None License: CC0-1.0 # docs Files: *.dox *.md src/util/README.dpinyin tools/qdbusxml2cpp/README Copyright: UnionTech Software Technology Co., Ltd. License: CC-BY-4.0 # doxygen src Files: docs/src/* Copyright: None License: CC0-1.0 # interface Files: include/DtkCore/D* Copyright: None License: CC0-1.0 # others Files: src/util/resources/dpinyin.dict tests/data/LGPLv3.txt Copyright: None License: CC0-1.0 Files: src/log/* Copyright: UnionTech Software Technology Co., Ltd. License: LGPL-3.0-or-later #doxygentheme Files: docs/doxygentheme/* Copyright: Copyright (c) 2021 - 2022 jothepro License: MIT #reference Files: docs/references/* Copyright: UnionTech Software Technology Co., Ltd. License: CC-BY-4.0 Files: toolGenerate/**/* Copyright: None License: CC0-1.0 dtkcore-5.7.12/.syncexclude000066400000000000000000000003651476226660600156130ustar00rootroot00000000000000# Paths that will be exclude from synchronize workflow # Please use relative path which use project directory as root # Notice that # * .git # * debian # * archlinux # * .obs # * .github # are always ignored linglong.yaml conanfile.py dtkcore-5.7.12/CHANGELOG.md000066400000000000000000000221201476226660600150660ustar00rootroot00000000000000 ## 2.0.14 (2019-05-23) #### Bug Fixes * **DSettings:** crash when calling getOption() if option doesn't exist ([90ac734b](https://github.com/linuxdeepin/dtkcore/commit/90ac734b872203ea698808a7197aa7a9c7e2b5bd)) ## 2.0.12 (2019-04-18) ## 2.0.11 (2019-04-17) #### Bug Fixes * Cross-builds incorrectly, built packages contain paths from build architecture ([8d32577a](https://github.com/linuxdeepin/dtkcore/commit/8d32577a89e54b5c9c834caae83d98e50f59df77)) * https://github.com/linuxdeepin/dtkcore/issues/10 ([3f99873a](https://github.com/linuxdeepin/dtkcore/commit/3f99873a786f6830688ecd0d8d2e2bf8dfb63ce0)) ## 2.0.10 (2019-03-27) #### Bug Fixes * crash at application ([d852a218](https://github.com/linuxdeepin/dtkcore/commit/d852a21811f9f86e04274fc9f732d7c7a210ef3f)) #### Features * add DNotifySender ([89bbcd7c](https://github.com/linuxdeepin/dtkcore/commit/89bbcd7c3821985bb2bca51247394fd4a65b25bf)) ## 2.0.9.17 (2019-02-26) ## 2.0.9.16 (2019-02-26) #### Bug Fixes * deepin-os-release support cpu model and other info query ([cbeb47c9](https://github.com/linuxdeepin/dtkcore/commit/cbeb47c97e31d2b5dd3c198c60ee74332fecb293)) ## 2.0.9.15 (2019-01-25) #### Bug Fixes * failed build the deepin-os-release on Qt 5.7.1 ([8bae8654](https://github.com/linuxdeepin/dtkcore/commit/8bae8654bdb20a7f773130d22b9db139460ba575)) * use main project c/cxx/ld flags on build deepin-os-release ([86dbd507](https://github.com/linuxdeepin/dtkcore/commit/86dbd507c1b3b101c1816f091782430ec1ce20ce)) ## 2.0.9.14 (2019-01-02) ## 2.0.9.13 (2018-12-28) ## 2.0.9.12 (2018-12-24) #### Bug Fixes * **DPathBuf:** missing default constructor ([74374cb4](https://github.com/linuxdeepin/dtkcore/commit/74374cb4cf0245ab1fe73f62fe0d13566f945db3)) #### Features * support connan build ([ba2d213f](https://github.com/linuxdeepin/dtkcore/commit/ba2d213fd6c7e36e118288305e5892c339250623)) ## 2.0.9.11 (2018-12-14) ## 2.0.9.10 (2018-12-05) #### Bug Fixes * include unistd.h instead of sys/unistd.h ([39c50a13](https://github.com/linuxdeepin/dtkcore/commit/39c50a1398c34123e3806a3060a4c64e7f45ed68)) * url encoding ([4a6b7b61](https://github.com/linuxdeepin/dtkcore/commit/4a6b7b61bb3ad9ab417eda69249b5e9aced0aa97)) ## 2.0.9.9 (2018-11-19) #### Features * add DRecentManager class. ([a2defafd](https://github.com/linuxdeepin/dtkcore/commit/a2defafdcf57078461221c665e322287a43d24a8)) #### Bug Fixes * compatibility with Qt 5.6 ([0ec7f3ce](https://github.com/linuxdeepin/dtkcore/commit/0ec7f3ce389b323ecb2b103801c1cd1d55f100fa)) * **drecentmanager:** * xbel file does not exist. ([c57ffe71](https://github.com/linuxdeepin/dtkcore/commit/c57ffe714f26b1a8a8859e2ffbeeed3d75ee11a1)) * uniform url format. ([413a8988](https://github.com/linuxdeepin/dtkcore/commit/413a8988116708ab8bcf9efbb9bc8f52e048efa5)) * url encoded. ([e234a8cc](https://github.com/linuxdeepin/dtkcore/commit/e234a8cc5ad9d2c14a16950838115c4f2f27c605)) * **recent:** chinese doc ([fb256461](https://github.com/linuxdeepin/dtkcore/commit/fb256461d1bdb0862b1a3a129978fc3932a6bcab)) ## 2.0.9.8 (2018-11-09) #### Bug Fixes * can't get correct disk size in some case ([20a12b62](https://github.com/linuxdeepin/dtkcore/commit/20a12b622ea7b01f0616c15a8af85e31fc2d36cb)) ## 2.0.9.5 (2018-10-26) #### Features * update version number for expermimental ([02b5d5c1](https://github.com/linuxdeepin/dtkcore/commit/02b5d5c1e01a05f57651b774b02cae31ef9a549f)) ## 2.0.9 (2018-07-20) #### Bug Fixes * remove qt symbols ([57ec78ba](https://github.com/linuxdeepin/dtkcore/commit/57ec78ba685a53692b0260d3d558d8b0915fc3e4)) * non array type value is wrong on parse josn file ([9f138664](https://github.com/linuxdeepin/dtkcore/commit/9f13866439d8d650893434594da023e7d331d866)) ### 2.0.8.1 (2018-05-14) #### Bug Fixes * update symbols ([f6c53cc4](https://github.com/linuxdeepin/dtkcore/commit/f6c53cc493c1bcf55dca54dbf500e2e484af73c9)) * add LIBDTKCORESHARED_EXPORT for windows ([6fb1096f](https://github.com/linuxdeepin/dtkcore/commit/6fb1096f6d0784937cf84f0e4ae1f5f7587085e5)) * **changelog:** update email format ([cb09a0ca](https://github.com/linuxdeepin/dtkcore/commit/cb09a0cadcf2fa0ba271b1d98d3b96a993eb892b)) ## 2.0.8 (2018-05-02) #### Features * add symbols ([048de455](https://github.com/linuxdeepin/dtkcore/commit/048de4551bdd770aca5e9c12798362f913061654)) ## 2.0.7 (2018-03-01) #### Bug Fixes * cmake link depends ([cdfcff9e](https://github.com/linuxdeepin/dtkcore/commit/cdfcff9e2f3e92bc6dbb45644d2714d6c4dbdda0)) * better static lib support ([99886406](https://github.com/linuxdeepin/dtkcore/commit/99886406a0cae849fad23286fdf64bb399e37da0)) * read settings value failed ([cf1c7698](https://github.com/linuxdeepin/dtkcore/commit/cf1c769893773794dff5a67c235c5d1f3234541a)) * set default should not use ([146529f6](https://github.com/linuxdeepin/dtkcore/commit/146529f6887e798606f2bf763ab8a760969bff26)) * fix dtk-settings install path ([1893cff3](https://github.com/linuxdeepin/dtkcore/commit/1893cff301dacb546a246a4f824dab68eac51351)) * develop package no install the "version.pri" file ([5667b562](https://github.com/linuxdeepin/dtkcore/commit/5667b562630565fca5abed690f3d3478dd3c7603)) * awk script failed ([524a3fa6](https://github.com/linuxdeepin/dtkcore/commit/524a3fa6021ee54db416503520aea65ef0e2c3a0)) * set default build version for debian changelog ([ec6e2a83](https://github.com/linuxdeepin/dtkcore/commit/ec6e2a8376c7aca7162b4fbb782b998c9a6ab630)) * set its value only if VERSION is empty ([1836000c](https://github.com/linuxdeepin/dtkcore/commit/1836000c49eb149a6495322c4cbb1474d5d48204)) #### Features * add hide support for group ([e7e4fb66](https://github.com/linuxdeepin/dtkcore/commit/e7e4fb669276fbce61c6378e74ae82573e7c0313)) * add get option interface ([d8682485](https://github.com/linuxdeepin/dtkcore/commit/d8682485a6737da83fb28f22335f1da1afb8956c)) * add group interface for DSettingsGroup ([c876180f](https://github.com/linuxdeepin/dtkcore/commit/c876180f535e3027dce63628f31379ef874367ed)) * support generate cmake with qt function ([524b0559](https://github.com/linuxdeepin/dtkcore/commit/524b055929b7be84375a45f9d10cbc3a0ecac6de)) * config pkg config with dtk_module ([137b9138](https://github.com/linuxdeepin/dtkcore/commit/137b91388d9b9db24c8136dd4e2c6e690a5712c5)) * support qt module ([17ca0de9](https://github.com/linuxdeepin/dtkcore/commit/17ca0de9156a320cea32208dcff2f8cdf7d6a237)) * add the "version.pri" file ([07aab9fd](https://github.com/linuxdeepin/dtkcore/commit/07aab9fd6478c83c7bae1062f64b4bd20b21869c)) * remove build version from install path ([3bf0bfb5](https://github.com/linuxdeepin/dtkcore/commit/3bf0bfb5f49c3e83d4c36cc33f219150bf3731d8)) * make version parser easier ([6d3b4ead](https://github.com/linuxdeepin/dtkcore/commit/6d3b4ead7080158d1d8977bf7cf99ae842e574ec)) * set verion when build ([9083dbd3](https://github.com/linuxdeepin/dtkcore/commit/9083dbd3e29bf9d06b1032901ba13848fa964f4c)) * add .qmake.conf file ([2890f643](https://github.com/linuxdeepin/dtkcore/commit/2890f643a57c3532ab623410f7c6c6dbfdd6788d)) * add DtkCore and dtkcore_config.h headers ([308a0cc4](https://github.com/linuxdeepin/dtkcore/commit/308a0cc41101499c04308b4ef3bb2fff4ab8d783)) * **DSettings:** support set default value ([5fe9bfd0](https://github.com/linuxdeepin/dtkcore/commit/5fe9bfd0a5e20cef7393639712302825b803db29)) ## 2.0.6 (2018-01-15) ## 2.0.5.3 (2017-12-27) #### Bug Fixes * Adapt lintian ([27df15df](https://github.com/linuxdeepin/dtkcore/commit/27df15df32788002491a24f06f098a5f849a4988)) * break forever loop for syncing backend data ([f70e500e](https://github.com/linuxdeepin/dtkcore/commit/f70e500ec2fd5c751e40833bdc4df586614bcff2)) #### Features * **util:** add dpinyin ([128d7d67](https://github.com/linuxdeepin/dtkcore/commit/128d7d678e921bc580dd732b14a454973397899c)) ## 2.0.5.2 (2017-11-28) #### Bug Fixes * make macosx build success ([af04bbe1](https://github.com/linuxdeepin/dtkcore/commit/af04bbe193a4b4251908f830d927ebdc8f4459e7)) * windows build failed ([66c4c812](https://github.com/linuxdeepin/dtkcore/commit/66c4c812eb29634710642f4e9d6b3d69cc692cb2)) #### Features * add macro D_DECL_DEPRECATED ([89e49868](https://github.com/linuxdeepin/dtkcore/commit/89e49868f113ef01c03bcf5b6846eec95c428382)) ## 2.0.5 (2017-11-06) #### Bug Fixes * build failed on used dbasefilewatcher.h project ([34fbe4b3](34fbe4b3)) * add miss libgsettings-qt-dev ([f61c1b54](f61c1b54)) * not select python version ([7e7e8832](7e7e8832)) #### Features * support gsettingsbackend, remove dsettings-key ([26a29800](26a29800)) * create gsettingsbackend ([b94b97b1](b94b97b1)) dtkcore-5.7.12/CMakeLists.txt000066400000000000000000000013001476226660600160120ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.13) set (DTK_VERSION "5.6.12" CACHE STRING "define project version") project (DtkCore VERSION ${DTK_VERSION} DESCRIPTION "DTK Core module" HOMEPAGE_URL "https://github.com/linuxdeepin/dtkcore" LANGUAGES CXX C ) if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX /usr) endif () include(GNUInstallDirs) include(CMakePackageConfigHelpers) if("${PROJECT_VERSION_MAJOR}" STREQUAL "5") set(QT_VERSION_MAJOR "5") elseif("${PROJECT_VERSION_MAJOR}" STREQUAL "6") set(QT_VERSION_MAJOR "6") set(DTK_VERSION_MAJOR "6") else() message(SEND_ERROR "not support Prject Version ${PROJECT_VERSION}.") endif() include(dtkcore.cmake) dtkcore-5.7.12/LICENSE000066400000000000000000001221621476226660600142710ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . dtkcore-5.7.12/LICENSES/000077500000000000000000000000001476226660600144655ustar00rootroot00000000000000dtkcore-5.7.12/LICENSES/BSD-3-Clause.txt000066400000000000000000000026641476226660600172200ustar00rootroot00000000000000Copyright (c) . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dtkcore-5.7.12/LICENSES/CC-BY-4.0.txt000066400000000000000000000411771476226660600163340ustar00rootroot00000000000000Creative Commons Attribution 4.0 International Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. Creative Commons Attribution 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 – Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. h. Licensor means the individual(s) or entity(ies) granting rights under this Public License. i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 – Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: A. reproduce and Share the Licensed Material, in whole or in part; and B. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 5. Downstream recipients. A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 – License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: A. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. Section 4 – Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 – Disclaimer of Warranties and Limitation of Liability. a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 – Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 – Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 – Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. dtkcore-5.7.12/LICENSES/CC0-1.0.txt000066400000000000000000000156101476226660600160720ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. dtkcore-5.7.12/LICENSES/LGPL-2.1-or-later.txt000066400000000000000000000624621476226660600200170ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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. Copyright (C) This library is free software; you can redistribute it 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. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. < signature of Ty Coon > , 1 April 1990 Ty Coon, President of Vice That's all there is to it! dtkcore-5.7.12/LICENSES/LGPL-3.0-or-later.txt000066400000000000000000001221621476226660600200110ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . dtkcore-5.7.12/README.md000066400000000000000000000032151476226660600145400ustar00rootroot00000000000000## Deepin Tool Kit Core Deepin Tool Kit (DtkCore) is the base development tool of all C++/Qt Developer work on Deepin. You should read the Deepin Application Specification firstly. 中文说明:[README.zh_CN.md](./README.zh_CN.md) ## Document 中文文档:[dtkcore文档](https://linuxdeepin.github.io/dtkcore/index.html) ## Dependencies ### Build dependencies * Qt >= 5.10 ## Compile option | **Compile option** | **meaning** | **Default state** | |--------------------|-------------|---------------| | BUILD_DOCS | Compile document | ON | | BUILD_TESTING | Compile test | Default is ON in debug mode | | BUILD_EXAMPLES | Compile example | ON | | BUILD_WITH_SYSTEMD | Support Systemd function | OFF | | BUILD_THEME | Add themes to the document | OFF | ## Installation ### Build from source code 1. Make sure you have installed all dependencies. 2. Build: ```bash mkdir build cd build cmake .. make ``` 3. Install: ```bash sudo make install ``` ## Getting help Any usage issues can ask for help via * [Telegram group](https://t.me/deepin) * [Matrix](https://matrix.to/#/#deepin-community:matrix.org) * [IRC (libera.chat)](https://web.libera.chat/#deepin-community) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## Getting involved We encourage you to report issues and contribute changes * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). ## License deepin-tool-kit is licensed under [LGPL-3.0-or-later](LICENSE). dtkcore-5.7.12/README.zh_CN.md000066400000000000000000000030251476226660600155370ustar00rootroot00000000000000## Deepin Tool Kit Core Deepin Tool Kit Core(DtkCore) 是所有C++/Qt开发人员在Deepin上工作的基础开发工具. 您应该首先阅读 Deepin应用程序规范. ## 文档 中文文档:[dtkcore文档](https://linuxdeepin.github.io/dtkcore/index.html) ## 依赖 ### 编译依赖 * Qt >= 5.10 ## 编译选项 | **编译选项** | **含义** | **默认状态** | |--------------------|-------------|---------------| | BUILD_DOCS | 编译文档 | ON | | BUILD_TESTING | 编译测试 | Debug模式下默认为ON | | BUILD_EXAMPLES | 编译示例 | ON | | BUILD_WITH_SYSTEMD | 支持Systmed功能 | OFF | | BUILD_THEME | 为文档添加主题 | OFF | ## 安装 ### 从源代码构建 1. 确保已经安装了所有的编译依赖. 2. 构建: ```bash mkdir build cd build cmake .. make ``` 3. 安装: ```bash sudo make install ``` ## 帮助 任何使用问题都可以通过以下方式寻求帮助: * [Telegram 群组](https://t.me/deepin) * [Matrix](https://matrix.to/#/#deepin-community:matrix.org) * [IRC (libera.chat)](https://web.libera.chat/#deepin-community) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## 参与贡献 我们鼓励您报告问题并作出更改 * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) ## 协议 DTK工具包遵循协议 [LGPL-3.0-or-later](LICENSE). dtkcore-5.7.12/archlinux/000077500000000000000000000000001476226660600152555ustar00rootroot00000000000000dtkcore-5.7.12/archlinux/PKGBUILD000066400000000000000000000021651476226660600164050ustar00rootroot00000000000000# Maintainer: justforlxz pkgname=dtkcore-git pkgver=5.6.16 pkgrel=1 sourcename=dtkcore sourcetars=("$sourcename"_"$pkgver".tar.xz) sourcedir="$sourcename" pkgdesc='DTK core modules' arch=('x86_64' 'aarch64') url="https://github.com/linuxdeepin/dtkcore" license=('LGPL3') depends=('deepin-desktop-base-git' 'gsettings-qt' 'dtkcommon-git' 'lshw' 'uchardet' 'icu' 'libsystemd' 'spdlog') makedepends=('git' 'qt5-tools' 'ninja' 'cmake' 'doxygen') conflicts=('dtkcore') provides=('dtkcore') groups=('deepin-git') source=("${sourcetars[@]}") sha512sums=('SKIP') build() { cd $sourcedir version=$(echo $pkgver | awk -F'[+_~-]' '{print $1}') cmake \ -GNinja \ -DMKSPECS_INSTALL_DIR=lib/qt/mkspecs/modules \ -DBUILD_DOCS=ON \ -DBUILD_WITH_SYSTEMD=ON \ -DBUILD_EXAMPLES=OFF \ -DQCH_INSTALL_DESTINATION=share/doc/qt \ -DCMAKE_INSTALL_LIBDIR=lib \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_BUILD_TYPE=Release \ -DD_DSG_APP_DATA_FALLBACK=/var/dsg/appdata \ -DBUILD_WITH_SYSTEMD=ON \ -DDTK_VERSION=$version ninja } package() { cd $sourcedir DESTDIR="$pkgdir" ninja install } dtkcore-5.7.12/cmake/000077500000000000000000000000001476226660600143405ustar00rootroot00000000000000dtkcore-5.7.12/cmake/DtkCMake/000077500000000000000000000000001476226660600157635ustar00rootroot00000000000000dtkcore-5.7.12/cmake/DtkCMake/DtkCMakeConfig.cmake000066400000000000000000000050471476226660600215440ustar00rootroot00000000000000function(addDefinitions macro) string(TOUPPER ${macro} macro) add_definitions(-D${macro}) endfunction() add_definitions(-DQ_HOST_NAME=\"${CMAKE_HOST_SYSTEM_PROCESSOR}\") addDefinitions(Q_HOST_${CMAKE_HOST_SYSTEM_PROCESSOR}) find_package(DtkCore REQUIRED) set(DEEPIN_OS_RELEASE_TOOL_PATH ${DtkCore_TOOL_DIRS}) set(DEEPIN_OS_RELEASE_TOOL ${DEEPIN_OS_RELEASE_TOOL_PATH}/deepin-os-release) if(NOT EXISTS "${DEEPIN_OS_RELEASE_TOOL}") message(FATAL_ERROR "\"${DEEPIN_OS_RELEASE_TOOL}\" is not exists. Install \"dtkcore-bin\" first") endif() function(formatString string) string(REGEX REPLACE "\\s+" "_" string ${string}) endfunction() macro(execDeepinOsRelease args output) exec_program(${DEEPIN_OS_RELEASE_TOOL} ARGS ${args} OUTPUT_VARIABLE ${output} RETURN_VALUE exitCode) if(NOT ${exitCode} EQUAL 0) message(FATAL_ERROR "exec deepin-os-release failed, with args: ${args}, error message: ${output}") endif() endmacro() execDeepinOsRelease(--deepin-type DEEPIN_OS_TYPE) execDeepinOsRelease(--deepin-version DEEPIN_OS_VERSION) execDeepinOsRelease(--product-type CMAKE_PLATFORM_ID) execDeepinOsRelease(--product-version CMAKE_PLATFORM_VERSION) if("${CMAKE_PLATFORM_ID}" STREQUAL "") message(WARNING "No value of the \"--product-type\" in the process \"${DEEPIN_OS_RELEASE_TOOL}\"") else() formatString(CMAKE_PLATFORM_ID) message("OS: ${CMAKE_PLATFORM_ID}, Version: ${CMAKE_PLATFORM_VERSION}") if(NOT "${CMAKE_PLATFORM_ID}" STREQUAL "") addDefinitions(Q_OS_${CMAKE_PLATFORM_ID}) string(TOUPPER ${CMAKE_PLATFORM_ID} CMAKE_PLATFORM_ID) set(OS_${CMAKE_PLATFORM_ID} TRUE) endif() formatString(CMAKE_PLATFORM_VERSION) add_definitions(-DQ_OS_VERSION=\"${CMAKE_PLATFORM_VERSION}\") #uos base with deepin if("${CMAKE_PLATFORM_ID}" STREQUAL "UOS") addDefinitions(Q_OS_DEEPIN) set(OS_DEEPIN TRUE) endif() endif() if("${DEEPIN_OS_TYPE}" STREQUAL "") message(WARNING "No value of the \"--deepin-type\" in the process \"${DEEPIN_OS_RELEASE_TOOL}\"") else() formatString(DEEPIN_OS_TYPE) message("Deepin OS Type: ${DEEPIN_OS_TYPE}") message("Deepin OS Version: ${DEEPIN_OS_VERSION}") if(NOT "${DEEPIN_OS_TYPE}" STREQUAL "") addDefinitions(Q_OS_DEEPIN_${DEEPIN_OS_TYPE}) addDefinitions(DEEPIN_DDE) string(TOUPPER ${DEEPIN_OS_TYPE} DEEPIN_OS_TYPE) set(OS_DEEPIN_${DEEPIN_OS_TYPE} TRUE) set(DEEPIN_DDE TRUE) endif() formatString(DEEPIN_OS_VERSION) add_definitions(-DQ_OS_DEEPIN_VERSION=\"${DEEPIN_OS_VERSION}\") endif() dtkcore-5.7.12/cmake/DtkCMake/DtkCMakeConfig.cmake.in000066400000000000000000000050721476226660600221470ustar00rootroot00000000000000function(addDefinitions macro) string(TOUPPER ${macro} macro) add_definitions(-D${macro}) endfunction() add_definitions(-DQ_HOST_NAME=\"${CMAKE_HOST_SYSTEM_PROCESSOR}\") addDefinitions(Q_HOST_${CMAKE_HOST_SYSTEM_PROCESSOR}) find_package(Dtk@DTK_VERSION_MAJOR@Core REQUIRED) set(DEEPIN_OS_RELEASE_TOOL_PATH ${DtkCore_TOOL_DIRS}) set(DEEPIN_OS_RELEASE_TOOL ${DEEPIN_OS_RELEASE_TOOL_PATH}/deepin-os-release) if(NOT EXISTS "${DEEPIN_OS_RELEASE_TOOL}") message(FATAL_ERROR "\"${DEEPIN_OS_RELEASE_TOOL}\" is not exists. Install \"dtkcore-bin\" first") endif() function(formatString string) string(REGEX REPLACE "\\s+" "_" string ${string}) endfunction() macro(execDeepinOsRelease args output) exec_program(${DEEPIN_OS_RELEASE_TOOL} ARGS ${args} OUTPUT_VARIABLE ${output} RETURN_VALUE exitCode) if(NOT ${exitCode} EQUAL 0) message(FATAL_ERROR "exec deepin-os-release failed, with args: ${args}, error message: ${output}") endif() endmacro() execDeepinOsRelease(--deepin-type DEEPIN_OS_TYPE) execDeepinOsRelease(--deepin-version DEEPIN_OS_VERSION) execDeepinOsRelease(--product-type CMAKE_PLATFORM_ID) execDeepinOsRelease(--product-version CMAKE_PLATFORM_VERSION) if("${CMAKE_PLATFORM_ID}" STREQUAL "") message(WARNING "No value of the \"--product-type\" in the process \"${DEEPIN_OS_RELEASE_TOOL}\"") else() formatString(CMAKE_PLATFORM_ID) message("OS: ${CMAKE_PLATFORM_ID}, Version: ${CMAKE_PLATFORM_VERSION}") if(NOT "${CMAKE_PLATFORM_ID}" STREQUAL "") addDefinitions(Q_OS_${CMAKE_PLATFORM_ID}) string(TOUPPER ${CMAKE_PLATFORM_ID} CMAKE_PLATFORM_ID) set(OS_${CMAKE_PLATFORM_ID} TRUE) endif() formatString(CMAKE_PLATFORM_VERSION) add_definitions(-DQ_OS_VERSION=\"${CMAKE_PLATFORM_VERSION}\") #uos base with deepin if("${CMAKE_PLATFORM_ID}" STREQUAL "UOS") addDefinitions(Q_OS_DEEPIN) set(OS_DEEPIN TRUE) endif() endif() if("${DEEPIN_OS_TYPE}" STREQUAL "") message(WARNING "No value of the \"--deepin-type\" in the process \"${DEEPIN_OS_RELEASE_TOOL}\"") else() formatString(DEEPIN_OS_TYPE) message("Deepin OS Type: ${DEEPIN_OS_TYPE}") message("Deepin OS Version: ${DEEPIN_OS_VERSION}") if(NOT "${DEEPIN_OS_TYPE}" STREQUAL "") addDefinitions(Q_OS_DEEPIN_${DEEPIN_OS_TYPE}) addDefinitions(DEEPIN_DDE) string(TOUPPER ${DEEPIN_OS_TYPE} DEEPIN_OS_TYPE) set(OS_DEEPIN_${DEEPIN_OS_TYPE} TRUE) set(DEEPIN_DDE TRUE) endif() formatString(DEEPIN_OS_VERSION) add_definitions(-DQ_OS_DEEPIN_VERSION=\"${DEEPIN_OS_VERSION}\") endif() dtkcore-5.7.12/cmake/DtkDConfig/000077500000000000000000000000001476226660600163145ustar00rootroot00000000000000dtkcore-5.7.12/cmake/DtkDConfig/DtkDConfigConfig.cmake000066400000000000000000000073221476226660600224240ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 - 2023 Uniontech Software Technology Co.,Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later # This cmake file is used to deploy files that dconfig's meta and override configure. include(CMakeParseArguments) # get subpath according `FILE` and `BASE`. # e.g: FILE = /a/b/c/d/foo.json, BASE = /a/b, then return SUBPATH = /c/d/ function(get_subpath FILE BASE SUBPATH) get_filename_component(BASE_FILE_PATH ${BASE} REALPATH) get_filename_component(FILE_PATH ${FILE} REALPATH) string(REPLACE ${BASE_FILE_PATH} "" SUBPATH_FILE_NAME ${FILE_PATH}) get_filename_component(SUBPATH_PATH ${SUBPATH_FILE_NAME} DIRECTORY) set(${SUBPATH} ${SUBPATH_PATH} PARENT_SCOPE) endfunction() if(NOT DEFINED DSG_DATA_DIR) set(DSG_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share/dsg) endif() add_definitions(-DDSG_DATA_DIR=\"${DSG_DATA_DIR}\") # deploy some `meta` 's configure. # # FILES - deployed files. # BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. # APPID - working for the app. # COMMONID - working for common. # # e.g: # dtk_add_config_meta_files(APPID dconfigexample BASE ./configs FILES ./configs/example.json ./configs/a/example.json) # function(dtk_add_config_meta_files) set(oneValueArgs BASE APPID COMMONID) set(multiValueArgs FILES) cmake_parse_arguments(METAITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) foreach(_current_FILE ${METAITEM_FILES}) set(SUBPATH "") if (DEFINED METAITEM_BASE) GET_SUBPATH(${_current_FILE} ${METAITEM_BASE} SUBPATH) endif() if (DEFINED METAITEM_APPID) install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/${METAITEM_APPID}/${SUBPATH}) elseif (DEFINED METAITEM_COMMONID) install(FILES ${_current_FILE} DESTINATION ${DSG_DATA_DIR}/configs/${SUBPATH}) else() message(FATAL_ERROR "Please set APPID or COMMONID for the meta item." ${_current_FILE}) endif() endforeach() endfunction() # deploy some `meta` 's override configure. # # configuration for the `meta_name` 's override configure. # # FILES - deployed files. # BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. # APPID - working for the app, if it's empty, working for all app. # META_NAME - override for the meta configure. # # e.g : #dtk_add_config_override_files(APPID dconfigexample BASE ./configs META_NAME example FILES ./configs/dconf-example.override.json ./configs/a/dconf-example.override.a.json) # function(dtk_add_config_override_files) set(options) set(oneValueArgs BASE APPID META_NAME) set(multiValueArgs FILES) cmake_parse_arguments(OVERRIDEITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if (NOT DEFINED OVERRIDEITEM_META_NAME) message(FATAL_ERROR "Please set meta_name for the override configuration." ${FILES}) endif() foreach(_current_FILE ${OVERRIDEITEM_FILES}) set(SUBPATH "") if (DEFINED OVERRIDEITEM_BASE) GET_SUBPATH(${_current_FILE} ${OVERRIDEITEM_BASE} SUBPATH) endif() if (DEFINED OVERRIDEITEM_APPID) install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_APPID}/${OVERRIDEITEM_META_NAME}/${SUBPATH}) else() install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_META_NAME}/${SUBPATH}) endif() endforeach() endfunction() # deprecated since dtk6 function(dconfig_meta_files) dtk_add_config_meta_files(${ARGV}) endfunction() function(dconfig_override_files) dtk_add_config_override_files(${ARGV}) endfunction() dtkcore-5.7.12/cmake/DtkDConfig/DtkDConfigConfig.cmake.in000066400000000000000000000070511476226660600230300ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 - 2023 Uniontech Software Technology Co.,Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later # This cmake file is used to deploy files that dconfig's meta and override configure. include(CMakeParseArguments) # get subpath according `FILE` and `BASE`. # e.g: FILE = /a/b/c/d/foo.json, BASE = /a/b, then return SUBPATH = /c/d/ function(get_subpath FILE BASE SUBPATH) get_filename_component(BASE_FILE_PATH ${BASE} REALPATH) get_filename_component(FILE_PATH ${FILE} REALPATH) string(REPLACE ${BASE_FILE_PATH} "" SUBPATH_FILE_NAME ${FILE_PATH}) get_filename_component(SUBPATH_PATH ${SUBPATH_FILE_NAME} DIRECTORY) set(${SUBPATH} ${SUBPATH_PATH} PARENT_SCOPE) endfunction() if(NOT DEFINED DSG_DATA_DIR) set(DSG_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share/dsg) endif() add_definitions(-DDSG_DATA_DIR=\"${DSG_DATA_DIR}\") # deploy some `meta` 's configure. # # FILES - deployed files. # BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. # APPID - working for the app. # COMMONID - working for common. # # e.g: # dtk_add_config_meta_files(APPID dconfigexample BASE ./configs FILES ./configs/example.json ./configs/a/example.json) # function(dtk_add_config_meta_files) set(oneValueArgs BASE APPID COMMONID) set(multiValueArgs FILES) cmake_parse_arguments(METAITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) foreach(_current_FILE ${METAITEM_FILES}) set(SUBPATH "") if (DEFINED METAITEM_BASE) GET_SUBPATH(${_current_FILE} ${METAITEM_BASE} SUBPATH) endif() if (DEFINED METAITEM_APPID) install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/${METAITEM_APPID}/${SUBPATH}) elseif (DEFINED METAITEM_COMMONID) install(FILES ${_current_FILE} DESTINATION ${DSG_DATA_DIR}/configs/${SUBPATH}) else() message(FATAL_ERROR "Please set APPID or COMMONID for the meta item." ${_current_FILE}) endif() endforeach() endfunction() # deploy some `meta` 's override configure. # # configuration for the `meta_name` 's override configure. # # FILES - deployed files. # BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. # APPID - working for the app, if it's empty, working for all app. # META_NAME - override for the meta configure. # # e.g : #dtk_add_config_override_files(APPID dconfigexample BASE ./configs META_NAME example FILES ./configs/dconf-example.override.json ./configs/a/dconf-example.override.a.json) # function(dtk_add_config_override_files) set(options) set(oneValueArgs BASE APPID META_NAME) set(multiValueArgs FILES) cmake_parse_arguments(OVERRIDEITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if (NOT DEFINED OVERRIDEITEM_META_NAME) message(FATAL_ERROR "Please set meta_name for the override configuration." ${FILES}) endif() foreach(_current_FILE ${OVERRIDEITEM_FILES}) set(SUBPATH "") if (DEFINED OVERRIDEITEM_BASE) GET_SUBPATH(${_current_FILE} ${OVERRIDEITEM_BASE} SUBPATH) endif() if (DEFINED OVERRIDEITEM_APPID) install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_APPID}/${OVERRIDEITEM_META_NAME}/${SUBPATH}) else() install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_META_NAME}/${SUBPATH}) endif() endforeach() endfunction() @DCONFIG_DEPRECATED_FUNCS@ dtkcore-5.7.12/cmake/DtkTools/000077500000000000000000000000001476226660600161035ustar00rootroot00000000000000dtkcore-5.7.12/cmake/DtkTools/DtkDBusMacros.cmake000066400000000000000000000053221476226660600215540ustar00rootroot00000000000000# Copyright 2005-2011 Kitware, Inc. # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause include(MacroAddFileDependencies) include(CMakeParseArguments) function(dtk_add_dbus_interface _sources _interface _relativename) get_filename_component(_infile ${_interface} ABSOLUTE) get_filename_component(_basepath ${_relativename} DIRECTORY) get_filename_component(_basename ${_relativename} NAME) set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.h") set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.cpp") if(${QT_VERSION_MAJOR} EQUAL "5") if(_basepath) set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_basename}.moc") else() set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc") endif() else() if(_basepath) set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/moc_${_basename}.cpp") else() set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp") endif() endif() get_source_file_property(_nonamespace ${_interface} NO_NAMESPACE) if(_nonamespace) set(_params -N -m) else() set(_params -m) endif() get_source_file_property(_skipincludeannotations ${_interface} SKIP_INCLUDE_ANNOTATIONS) if(_skipincludeannotations) set(_params ${_params} -S) endif() get_source_file_property(_classname ${_interface} CLASSNAME) if(_classname) set(_params ${_params} -c ${_classname}) endif() get_source_file_property(_include ${_interface} INCLUDE) if(_include) set(_params ${_params} -i ${_include}) endif() add_custom_command(OUTPUT "${_impl}" "${_header}" COMMAND ${DTK_XML2CPP} ${_params} -p ${_relativename} ${_infile} DEPENDS ${_infile} ${DTK_XML2CPP} VERBATIM ) set_source_files_properties("${_impl}" "${_header}" PROPERTIES SKIP_AUTOMOC TRUE SKIP_AUTOUIC TRUE ) qt_generate_moc("${_header}" "${_moc}") list(APPEND ${_sources} "${_impl}" "${_header}") set_property(SOURCE "${_impl}" APPEND PROPERTY OBJECT_DEPENDS "${_moc}") set(${_sources} ${${_sources}} PARENT_SCOPE) endfunction() function(dtk_add_dbus_interfaces _sources) foreach(_current_FILE ${ARGN}) get_filename_component(_infile ${_current_FILE} ABSOLUTE) get_filename_component(_basename ${_current_FILE} NAME) # get the part before the ".xml" suffix string(TOLOWER ${_basename} _basename) string(REGEX REPLACE "(.*\\.)?([^\\.]+)\\.xml" "\\2" _basename ${_basename}) dtk_add_dbus_interface(${_sources} ${_infile} ${_basename}interface) endforeach() set(${_sources} ${${_sources}} PARENT_SCOPE) endfunction() dtkcore-5.7.12/cmake/DtkTools/DtkDConfigMacros.cmake000066400000000000000000000027011476226660600222260ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. # SPDX-License-Identifier: LGPL-3.0-or-later include(MacroAddFileDependencies) include(CMakeParseArguments) # Define the helper function function(dtk_add_config_to_cpp OUTPUT_VAR JSON_FILE) if(NOT EXISTS ${JSON_FILE}) message(FATAL_ERROR "JSON file ${JSON_FILE} does not exist.") endif() cmake_parse_arguments( "arg" "" "OUTPUT_FILE_NAME;CLASS_NAME" "" ${ARGN} ) # Generate the output header file name get_filename_component(FILE_NAME_WLE ${JSON_FILE} NAME_WLE) if(DEFINED arg_OUTPUT_FILE_NAME) set(OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${arg_OUTPUT_FILE_NAME}") else() set(OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/dconfig_${FILE_NAME_WLE}.hpp") endif() # Check if CLASS_NAME is set if(DEFINED arg_CLASS_NAME) set(CLASS_NAME_ARG -c ${arg_CLASS_NAME}) else() set(CLASS_NAME_ARG "") endif() # Add a custom command to run dconfig2cpp add_custom_command( OUTPUT ${OUTPUT_HEADER} COMMAND ${DTK_DCONFIG2CPP} -o ${OUTPUT_HEADER} ${CLASS_NAME_ARG} ${JSON_FILE} DEPENDS ${JSON_FILE} ${DTK_XML2CPP} COMMENT "Generating ${OUTPUT_HEADER} from ${JSON_FILE}" VERBATIM ) # Add the generated header to the specified output variable set(${OUTPUT_VAR} ${${OUTPUT_VAR}} ${OUTPUT_HEADER} PARENT_SCOPE) endfunction() dtkcore-5.7.12/cmake/DtkTools/DtkSettingsToolsMacros.cmake000066400000000000000000000053571476226660600235500ustar00rootroot00000000000000#============================================================================= # Copyright 2019 Deepin Technology Co., Ltd. # Copyright 2019 Gary Wang # 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 authors nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= function(DTK_CREATE_I18N_FROM_JSON _generated_file_list _input_json_file _output_cpp_file_name) set (generated_file_list) # 0(failed) or 1(succeeded) files in the list. get_filename_component(_input_json_abs_path ${_input_json_file} ABSOLUTE) get_filename_component(_input_json_abs_dir ${_input_json_abs_path} DIRECTORY) set (_output_cpp_abs_path ${_input_json_abs_dir}/${_output_cpp_file_name}) if (DTK_SETTINGS_TOOLS_FOUND) add_custom_command(OUTPUT ${_output_cpp_abs_path} COMMAND ${DTK_SETTINGS_TOOLS_EXECUTABLE} ARGS ${_input_json_abs_path} -o ${_output_cpp_abs_path} DEPENDS ${_input_json_abs_path} VERBATIM) list(APPEND generated_file_list ${_output_cpp_abs_path}) else () message (WARNING "The dtk-settings tools could not be found at ${DTK_SETTINGS_TOOLS_EXECUTABLE}") message (WARNING "Package distributor may create a separated package for tools like `libdtkcore-bin`.") endif () set(${_generated_file_list} ${generated_file_list} PARENT_SCOPE) endfunction() dtkcore-5.7.12/cmake/DtkTools/DtkToolsConfig.cmake.in000066400000000000000000000012621476226660600224040ustar00rootroot00000000000000include(CMakeFindDependencyMacro) find_dependency(Dtk@DTK_VERSION_MAJOR@Core REQUIRED) set (DTK_SETTINGS_TOOLS_EXECUTABLE ${DtkCore_TOOL_DIRS}/dtk-settings) if (EXISTS ${DTK_SETTINGS_TOOLS_EXECUTABLE}) set(DTK_SETTINGS_TOOLS_FOUND TRUE) endif () include("${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@SettingsToolsMacros.cmake") include("${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@ToolsTargets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/DtkDBusMacros.cmake") include("${CMAKE_CURRENT_LIST_DIR}/DtkDConfigMacros.cmake") get_target_property(DTK_XML2CPP Dtk@DTK_VERSION_MAJOR@::Xml2Cpp LOCATION) get_target_property(DTK_DCONFIG2CPP Dtk@DTK_VERSION_MAJOR@::DConfig2Cpp LOCATION) dtkcore-5.7.12/conanfile.py000066400000000000000000000066171476226660600156020ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later from conans import ConanFile, tools class DtkcoreConan(ConanFile): name = 'dtkcore' version = '2.0.9' license = 'GPL' author = 'Iceyer me@iceyer.net' url = 'https://github.com/linuxdeepin/dtkcore' description = 'cross platform ui library' topics = ('qt', 'dtk') settings = 'os', 'compiler', 'build_type', 'arch' options = {'shared': [True, False]} default_options = 'shared=False' generators = 'qmake' exports_sources = '*' requires = 'jom_installer/1.1.2@bincrafters/stable', 'qt/5.6.3@iceyer/stable' def extend_include_path(self): return '%s/include/libdtk-%s/DCore' % (self.package_folder, self.version) # def source(self): # self.run('git clone https://github.com/linuxdeepin/dtkcore.git source') # self.run('cd source && git checkout 2.0.9.9') def build(self): outdir = self.build_folder # includedir = outdir + '/include' mkspecsdir = outdir + '/mkspecs' # libdir = outdir + '/lib' env_vars = tools.vcvars_dict(self.settings) env_vars['_CL_'] = '/utf-8' with tools.environment_append(env_vars): command = 'qmake -r' command += ' VERSION=%s' % self.version # command += ' CONFIG-=debug_and_release' # command += ' CONFIG-=debug_and_release_target' command += ' CONFIG+=release' command += ' PREFIX=%s' % outdir command += ' MKSPECS_INSTALL_DIR=%s' % mkspecsdir command += ' DTK_STATIC_LIB=YES' command += ' DTK_STATIC_TRANSLATION=YES' command += ' DTK_NO_MULTIMEDIA=YES' command += ' %s' % self.source_folder self.run(command) self.run('jom clean') self.run('jom') self.run('jom install') def package(self): self.deploy() outdir = self.build_folder self.copy('*', dst='include', src=outdir+'/include') self.copy('*.lib', dst='lib', src=outdir+'/lib') self.copy('*', dst='mkspecs', src=outdir+'/mkspecs') def package_info(self): self.cpp_info.libs = ['dtkcore'] self.cpp_info.includedirs.append(self.extend_include_path()) self.env_info.QMAKEPATH = self.cpp_info.rootpath self.env_info.QMAKEFEATURES = self.cpp_info.rootpath + '/mkspecs/features' def deploy(self): try: content = [] module_pri = self.build_folder + '/mkspecs/modules/qt_lib_dtkcore.pri' s = open(module_pri) for line in s.readlines(): if line.startswith('QT.dtkcore.tools'): line = 'QT.dtkcore.tools = %s\n' % ( self.package_folder + '/bin') elif line.startswith('QT.dtkcore.libs'): line = 'QT.dtkcore.libs = %s\n' % ( self.package_folder + '/lib') elif line.startswith('QT.dtkcore.includes'): line = 'QT.dtkcore.includes = %s\n' % ( self.extend_include_path()) content.append(line) s.close() # print('create module file', content) s = open(module_pri, 'w') s.writelines(content) except FileNotFoundError: print('skip update qt module file') dtkcore-5.7.12/debian/000077500000000000000000000000001476226660600145025ustar00rootroot00000000000000dtkcore-5.7.12/debian/changelog000066400000000000000000000276321476226660600163660ustar00rootroot00000000000000dtkcore (5.7.12) unstable; urgency=medium * feat: dconfig2cpp always add bindableFoo functions on Qt6 * feat: Add files generated by qdbusXML2cpp and DCONG2cpp -- YeShanShan Thu, 06 Mar 2025 17:29:21 +0800 dtkcore (5.7.11) unstable; urgency=medium * feat: dconfig2cpp generated codes supports qml * feat: export ProductType for QML * feat: async get dconfig value for DLog * feat: support auto generate the Qt code from a dconfig's json -- YeShanShan Thu, 27 Feb 2025 20:47:22 +0800 dtkcore (5.7.10) unstable; urgency=medium * Release 5.7.10 -- YeShanShan Thu, 13 Feb 2025 17:18:04 +0800 dtkcore (5.7.9) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Thu, 23 Jan 2025 09:07:08 +0000 dtkcore (5.7.8) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Tue, 14 Jan 2025 11:17:31 +0000 dtkcore (5.7.7) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Thu, 09 Jan 2025 09:28:38 +0000 dtkcore (5.7.6) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Thu, 02 Jan 2025 05:43:52 +0000 dtkcore (5.7.5) unstable; urgency=medium * fix: pidfd leak -- Deepin Packages Builder Thu, 12 Dec 2024 03:03:54 +0000 dtkcore (5.7.4) unstable; urgency=medium * fix: hasVtable is incorrect when destructing -- Deepin Packages Builder Tue, 03 Dec 2024 02:00:45 +0000 dtkcore (5.7.3) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Wed, 20 Nov 2024 02:19:06 +0000 dtkcore (5.7.2) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Wed, 13 Nov 2024 01:53:26 +0000 dtkcore (5.7.1) unstable; urgency=medium * feat: 增加智能终端设备类型 (#434) Thanks to Whale107 * fix: remove unnecessary link libraries * fix: DDBusInterface signal loss * fix(util): error appid from `getAppIdFromAbsolutePath` -- Deepin Packages Builder Wed, 16 Oct 2024 03:30:45 +0000 dtkcore (5.6.34) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Tue, 20 Aug 2024 05:03:51 +0000 dtkcore (5.6.32) unstable; urgency=medium * refactor: log files move to dtklog(Issue: #182) -- Deepin Packages Builder Mon, 08 Jul 2024 02:29:21 +0000 dtkcore (5.6.31) unstable; urgency=medium * chore: use '&&' and '||' instead of 'and' and 'or' -- Deepin Packages Builder Thu, 27 Jun 2024 09:11:34 +0000 dtkcore (5.6.30) unstable; urgency=medium * feat: 允许基于dtk开发的应用动态控制其日志输出等级(Task: 307567)(Influence: 允许基于dtk开发的应用动态控制其日志输出等级) * fix: lshw查询内存大小时返回多元素数组,修正解析过程(Bug: 228681)(Influence: DSysInfo::memoryInstalledSize解析过程) * fix: 从文件中读取deepinType和productType值时因为权限问题会失败(Influence: 正常显示版本和说明) * feat: 增加registerLoggingRulesWatcher接口(Task: 303379) * fix: 修复计算 build 版本号错误的问题(Influence: 构建版本号(BUILD_VERSION )) * feat: DeepinType类型增加军用版(Task: 316703)(Influence: DeepinType类型) * fix: 修复日志格式时间戳显示异常问题(Bug: 236239)(Influence: 使用DLogManager的应用日志输出格式) * chore: loggingrules config move to preference * refactor: remove LoggingRules interface * fix: crashed when access DSGApplication::id early * chore: fallback to dsgconfig value * fix(build): build faild on Qt 6.7.1 -- Deepin Packages Builder Thu, 30 May 2024 02:46:32 +0000 dtkcore (5.6.29) unstable; urgency=medium * chore: remove warning for dbusxml2cpp in qt6 -- Deepin Packages Builder Mon, 13 May 2024 03:02:53 +0000 dtkcore (5.6.28) unstable; urgency=medium * fix: fix undefined reference errors on spdlog 1.14.0 Thanks to hillwoodroc -- Deepin Packages Builder Mon, 29 Apr 2024 08:23:39 +0000 dtkcore (5.6.27) unstable; urgency=medium * fix: lossing value when save DConfig * fix(qdbusxml2cpp): support qt 6.7 -- Deepin Packages Builder Fri, 19 Apr 2024 08:55:35 +0000 dtkcore (5.6.26) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Tue, 26 Mar 2024 05:47:35 +0000 dtkcore (5.6.25) unstable; urgency=medium * chore: fix docs typo * feat: support to set appId for DConfig * fix: DConfig add check for name(Issue: #1211374) -- Deepin Packages Builder Mon, 11 Mar 2024 01:16:26 +0000 dtkcore (5.6.22) unstable; urgency=medium * Release 5.6.22 -- Deepin Packages Builder Wed, 10 Jan 2024 02:30:59 +0000 dtkcore (5.6.21) unstable; urgency=medium * fix: app blocked when AM is unavailable * chore: remove decltype(auto) for dutil * chore: fix relative path invalid link * feat: allow skip including headers of annotations(Issue: #147) -- Deepin Packages Builder Tue, 09 Jan 2024 01:45:43 +0000 dtkcore (5.6.20) unstable; urgency=medium * feat: add utils function * chore: Implement DSGApplication::getId * feat(dstandardpaths): add XDG_STATE_HOME * chore: keep order when deduplication * fix: log files limit not work * chore: add dtk dbus generate function -- Deepin Packages Builder Tue, 28 Nov 2023 05:40:53 +0000 dtkcore (5.6.19) unstable; urgency=medium * fix: Type error for qdbusxml2cpp * fix: correct Dtk6SettingsToolsMacros.cmake path * chore: add flag UserPublic(Issue: https://github.com/linuxdeepin/developer-center/issues/5928) -- Deepin Packages Builder Mon, 23 Oct 2023 07:33:19 +0000 dtkcore (5.6.18) unstable; urgency=medium * fix: Can't clear cache when reset for DConfig in FileBackend * feat: Add isDefaultValue for DConfig(Issue: #3) * fix: Compiling failed in lower libspdlog-dev * fix: missing parameter passing for synchronization * fix(build): skip failed unit test * chore(tools): show help if argc < 2 * fix: Compiling failed in libspdlog-dev before 1.4.0 Thanks to Shiroko * fix: cmake failure when env is null * chore: correct typos in DtkSettingsToolsMacros.cmake Thanks to Felix Yan * chore: dpinyin tweak(Issue: #109) -- Deepin Packages Builder Wed, 18 Oct 2023 06:01:45 +0000 dtkcore (5.6.17) unstable; urgency=medium * Release 5.6.17 -- Deepin Packages Builder Fri, 08 Sep 2023 15:12:36 +0800 dtkcore (5.6.16) unstable; urgency=medium * fix: FileAppender log level not set * chore: ut linked dtkcore instead of source code * chore: tweak CMakeLists * chore: support Qt 6.4 build * chore: qch docs tweak * chore: add DtkBuildHelper depends * chore: console with color at tty * fix: missing dependency qttools5-dev * feat: add synchronization workflow -- Deepin Packages Builder Tue, 22 Aug 2023 06:13:45 +0000 dtkcore (5.6.15) unstable; urgency=medium * chore: dlog example tweak -- Yixue Wang Fri, 11 Aug 2023 13:42:20 +0800 dtkcore (5.6.14) unstable; urgency=medium * chore: function need to be marked as override * chore: ignore doxygen-theme folder Thanks to Skye-rs * chore: change OUTPUT_DIR variable in cmake * chore: remove unused pro files * refactor!: deprecate some interfaces in dtk6 * fix: updateProp cannot convert to property type * fix: typo in xdg * chore: reduce compilation warnings Thanks to SPUER(Issue: #96) * chore(dcapmanager): RuntimeTime -> RuntimeDir * chore: Sync by https://github.com/linuxdeepin/.github/commit/559e91167d4919644f37bbcf123eb0651c1528ea(Influence: none) * chore: make test-recoverage.sh runable again * chore: add ut for DDbusSender * feat: add systembus send support * fix: internalPropSet nerver emit propertyChanged * chore: should include QVector headers * chore: dsysinfo tweak * chore: add some unit test -- Deepin Packages Builder Thu, 27 Jul 2023 06:56:33 +0000 dtkcore (5.6.13) unstable; urgency=medium * feat: DConfig add check for no existed item when override * fix(cmake): wrong use of option and wrong macro * fix: calling delay in DDBusSender(Issue: https://github.com/linuxdeepin/developer-center/issues/4415) * feat: DConfig add check for subpath(Issue: #54) * feat: DConfig exports metadir's implementation(Issue: #10) * fix(dccinterface): fix cannot get the right type * fix: DConfig's `subpathIsValid` produces error * fix(ut): failed ut * fix(build): build faild on Qt6 * fix: fix build failed due to gcc compiler bug * fix: ut_dfilewater failed on Qt6 * fix: DTextEncoding ut failed in Qt6. * fix: fix DTextEncoding warnings. * feat: support dtk6core build * feat: add DThreadUtils class * fix: move Qt CorePrivate to target private link * fix: qdbusxml2cpp-fix not in path * chore: remove ddbusinterface property cache * chore: remove libdtkcommon depends -- Deepin Packages Builder Sun, 25 Jun 2023 14:40:49 +0800 dtkcore (5.6.12) unstable; urgency=medium * Release 5.6.12 * add DLicenseInfo * cached memoryInstalledSize * FIX developer-center#4348 -- Deepin Packages Builder Mon, 15 May 2023 11:18:15 +0800 dtkcore (5.6.11) unstable; urgency=medium * Release 5.6.11 * add color to ConsoleAppender * remove build warning -- Deepin Packages Builder Mon, 08 May 2023 11:48:45 +0800 dtkcore (5.6.10) unstable; urgency=medium * Release 5.6.10 * support XDG_SESSION_DESKTOP set to DDE -- Deepin Packages Builder Mon, 17 Apr 2023 17:08:28 +0800 dtkcore (5.6.9) unstable; urgency=medium * Release 5.6.9 -- Deepin Packages Builder Mon, 03 Apr 2023 09:48:07 +0800 dtkcore (5.6.8) unstable; urgency=medium * Release 5.6.8 -- Deepin Packages Builder Wed, 22 Feb 2023 14:09:56 +0800 dtkcore (5.6.6) unstable; urgency=medium * Release 5.6.6 -- Deepin Packages Builder Tue, 21 Feb 2023 12:25:24 +0800 dtkcore (5.6.5) unstable; urgency=medium * Release 5.6.5 -- Deepin Packages Builder Thu, 02 Feb 2023 14:25:36 +0800 dtkcore (5.6.4) unstable; urgency=medium * Release 5.6.4 -- Deepin Packages Builder Fri, 06 Jan 2023 16:30:40 +0800 dtkcore (5.6.3) unstable; urgency=medium * Release 5.6.3 -- Deepin Packages Builder Mon, 12 Dec 2022 14:40:31 +0800 dtkcore (5.6.2.2) unstable; urgency=medium * release 5.6.2.2 -- Deepin Packages Builder Thu, 17 Nov 2022 17:41:10 +0800 dtkcore (5.6.2.1) unstable; urgency=medium * snipe release 5.6.2.1 -- Deepin Packages Builder Mon, 31 Oct 2022 16:53:16 +0800 dtkcore (5.6.2) unstable; urgency=medium * snipe release 5.6.2 -- Deepin Packages Builder Wed, 21 Sep 2022 13:57:29 +0800 dtkcore (5.6.0) unstable; urgency=medium * snipe release 5.6.0 -- Deepin Packages Builder Mon, 11 Jul 2022 17:47:56 +0800 dtkcore (5.0.3) unstable; urgency=medium * Release 5.0.3 -- Deepin Packages Builder Tue, 21 Sep 2019 13:31:03 +0800 dtkcore (5.0.0) unstable; urgency=medium * Release 5.0.0 -- Deepin Packages Builder Tue, 03 Sep 2019 08:47:03 +0800 dtkcore (2.0.8) unstable; urgency=medium * Release 2.0.8 -- Deepin Packages Builder Wed, 02 May 2018 10:52:03 +0800 dtkcore (0.3.3-1) unstable; urgency=medium * Initial release -- Deepin Packages Builder Mon, 10 Oct 2016 16:58:07 +0800 dtkcore-5.7.12/debian/control000066400000000000000000000026421476226660600161110ustar00rootroot00000000000000Source: dtkcore Section: libdevel Priority: optional Maintainer: Deepin Packages Builder Build-Depends: debhelper-compat ( =12), pkg-config, qttools5-dev-tools, qttools5-dev, qtbase5-private-dev, doxygen, libgsettings-qt-dev, libgtest-dev, libdtkcommon-dev, cmake, libuchardet-dev, libicu-dev, libdtklog-dev Standards-Version: 3.9.8 Package: libdtkcore5 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, lshw Multi-Arch: same Description: Deepin Tool Kit Core library DtkCore is base library of Deepin Qt/C++ applications. . This package contains the shared libraries. Package: libdtkcore5-bin Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore5( =${binary:Version}) Description: Deepin Tool Kit Core Utilities DtkCore is base devel library of Deepin Qt/C++ applications. . This package contains the utilities of DtkCore Package: libdtkcore-dev Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore5( =${binary:Version}), libdtkcommon-dev(>=5.6.16), libdtklog-dev Description: Deepin Tool Kit Core Devel library DtkCore is base devel library of Deepin Qt/C++ applications. . This package contains the header files and static libraries of DtkCore Package: libdtkcore-doc Architecture: any Description: Deepin Tool Kit Core (document) DtkCore is base devel library of Deepin Qt/C++ applications. . This package contains the doc files of DtkCore dtkcore-5.7.12/debian/copyright000066400000000000000000000017601476226660600164410ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: dtkcore Source: https://github.com/linuxdeepin/dtkcore Files: * Copyright: 2017 Deepin Technology Co., Ltd. License: LGPL-3+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This package 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 Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU Lesser General Public License version 3 can be found in "/usr/share/common-licenses/LGPL-3". dtkcore-5.7.12/debian/libdtkcore-dev.install000066400000000000000000000001411476226660600207640ustar00rootroot00000000000000usr/lib/*/lib*.so usr/include usr/lib/*/pkgconfig/*.pc usr/lib/*/cmake/*/*.cmake usr/lib/*/qt5/* dtkcore-5.7.12/debian/libdtkcore-doc.install000066400000000000000000000000361476226660600207560ustar00rootroot00000000000000usr/share/qt5/doc/dtkcore.qch dtkcore-5.7.12/debian/libdtkcore5-bin.install000066400000000000000000000000231476226660600210420ustar00rootroot00000000000000usr/*/*/DCore/bin/*dtkcore-5.7.12/debian/libdtkcore5.install000066400000000000000000000000241476226660600202750ustar00rootroot00000000000000usr/lib/*/lib*.so.* dtkcore-5.7.12/debian/rules000077500000000000000000000022271476226660600155650ustar00rootroot00000000000000#!/usr/bin/make -f DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk export QT_SELECT = qt5 export DEB_CXXFLAGS_MAINT_APPEND = -Ofast DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) VERSION = $(DEB_VERSION_UPSTREAM) PACK_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$1}') # Calculate build version: # 5.6.8 -> 0; 5.6.8.7 -> 7; 5.6.8+u001 -> 1; 5.6.8.7+u001 -> 7; 5.6.8.0+u001 -> 0 BUILD_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$1}' | awk -F'.' '{print $$4}' | sed 's/[^0-9]//g' | awk '{print int($$1)}') ifeq ($(BUILD_VER), 0) ifeq ($(shell expr $(shell echo "$(VERSION)" | awk -F. '{print NF-1}') '<' 3), 1) BUILD_VER=$(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$2}' | sed 's/[^0-9]//g' | awk '{print int($$1)}') endif endif %: dh $@ override_dh_auto_configure: dh_auto_configure -- -DBUILD_WITH_SYSTEMD=ON -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=ON -DBUILD_VERSION=$(BUILD_VER) -DDTK_VERSION=$(PACK_VER) -DD_DSG_APP_DATA_FALLBACK=/var/dsg/appdata #override_dh_auto_test: # echo "skip auto test" override_dh_makeshlibs: dh_makeshlibs -V "libdtkcore5 (>= $(shell echo $(VERSION) | cut -d '.' -f 1,2))" dtkcore-5.7.12/debian/source/000077500000000000000000000000001476226660600160025ustar00rootroot00000000000000dtkcore-5.7.12/debian/source/format000066400000000000000000000000151476226660600172110ustar00rootroot000000000000003.0 (native) dtkcore-5.7.12/docs/000077500000000000000000000000001476226660600142105ustar00rootroot00000000000000dtkcore-5.7.12/docs/CMakeLists.txt000066400000000000000000000072461476226660600167610ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.10) find_package (Doxygen REQUIRED) set (QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/qt${QT_VERSION_MAJOR}/doc CACHE STRING "QCH install location") set (DOXYGEN_GENERATE_HTML YES CACHE STRING "Doxygen HTML output") set (DOXYGEN_GENERATE_XML YES CACHE STRING "Doxygen XML output") set (DOXYGEN_GENERATE_QHP YES CACHE STRING "Doxygen QHP output") set (DOXYGEN_FILE_PATTERNS *.cpp *.h *.zh_CN.md *.zh_CN.dox CACHE STRING "Doxygen File Patterns") set (DOXYGEN_PROJECT_NUMBER ${CMAKE_PROJECT_VERSION} CACHE STRING "") # Should be the same as this project is using. set (DOXYGEN_EXTRACT_STATIC YES) set (DOXYGEN_OUTPUT_LANGUAGE "Chinese") if("${QT_VERSION_MAJOR}" STREQUAL "5") find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Help) else() find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS ToolsTools) endif() get_target_property(_qhelpgenerator_location Qt${QT_VERSION_MAJOR}::qhelpgenerator IMPORTED_LOCATION) if("${_qhelpgenerator_location}" STREQUAL "") set(_qhelpgenerator_location "qhelpgenerator") endif() set (DOXYGEN_QHG_LOCATION ${_qhelpgenerator_location} CACHE STRING "Doxygen QHG path") set (DOXYGEN_QHP_NAMESPACE "org.deepin.dtk.core") set (DOXYGEN_QCH_FILE "dtkcore.qch") set (DOXYGEN_QHP_VIRTUAL_FOLDER "dtkcore") set (DOXYGEN_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/docs/) set (DOXYGEN_HTML_EXTRA_STYLESHEET "" CACHE STRING "Doxygen custom stylesheet for HTML output") set (DOXYGEN_TAGFILES "qtcore.tags=qthelp://org.qt-project.qtcore/qtcore/" CACHE STRING "Doxygen tag files") set (DOXYGEN_IMAGE_PATH ${PROJECT_SOURCE_DIR}/docs/src) set (DOXYGEN_SOURCE_BROWSE "YES") set (BUILD_THEME OFF CACHE BOOL "Build doxgen theme") if(BUILD_THEME) if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/doxygen-theme") message(STATUS "doxygen-theme exists") else() execute_process(COMMAND git clone https://github.com/linuxdeepin/doxygen-theme.git --depth=1 WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} TIMEOUT 60 ) execute_process(COMMAND bash themesetting.sh WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen-theme/ ) endif() set (DOXYGEN_HTML_EXTRA_STYLESHEET "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome.css" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-sidebar-only.css" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css" ) set (DOXYGEN_HTML_EXTRA_FILES "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-paragraph-link.js" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-interactive-toc.js" ) set (DOXYGEN_GENERATE_TREEVIEW "YES") set (DOXYGEN_DISABLE_INDEX "NO") set (DOXYGEN_FULL_SIDEBAR "NO") set (DOXYGEN_HTML_HEADER "docs/doxygen-theme/doxygen-awesome-css/header.html") set (DOXYGEN_HTML_FOOTER "docs/doxygen-theme/doxygen-awesome-css/footer.html") endif() set (DOXYGEN_MACRO_EXPANSION "YES") set (DOXYGEN_PREDEFINED "DCORE_BEGIN_NAMESPACE=namespace Dtk { namespace Core {" "DCORE_END_NAMESPACE=}}" "DCORE_USE_NAMESPACE=using namespace Dtk::Core;" "Q_OS_LINUX=1" ) set (DOXYGEN_EXPAND_ONLY_PREDEF "YES") doxygen_add_docs (doxygen ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/docs ALL WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generate documentation via Doxygen" ) install (FILES ${PROJECT_BINARY_DIR}/docs/html/dtkcore.qch DESTINATION ${QCH_INSTALL_DESTINATION}) dtkcore-5.7.12/docs/MainPage.zh_CN.md000066400000000000000000000035651476226660600172240ustar00rootroot00000000000000\mainpage dtkcore @brief dtk # dtkcore ## 简介 dtkcore 是一个基于Qt的C++库,它提供了一些常用的工具类,以及一些基础的模块,如日志、插件、网络、线程、数据库、文件、图形、音频、视频、系统信息等 ## 使用 现在的dtkcore>=5.6版本使用CMake来管理各个模块,所以使用dtkcore时,需要先安装CMake(CMake>=3.10),然后需要在你的CMake项目中引入dtkcore的CMake模块,如下: ```cmake find_package(Dtk6Core REQUIRED) target_link_libraries( Dtk6::Core ) ``` ```qmake QT += dtkcore ``` ```bash pkg-config --cflags --libs dtk6core # pkgconfig find Dtk6Core in qmake # CONFIG += link_pkgconfig # PKGCONFIG += dtk6core # pkgconfig find Dtk6Core in cmake # find_package(PkgConfig REQUIRED) # pkg_check_modules(Dtk6Core REQUIRED IMPORTED_TARGET dtk6core) # target_link_libraries( PkgConfig::Dtk6Core ) ``` 以上示例仅为最小示例,并不能单独作为CMake项目使用,需要你自己添加其他的CMake模块,如Qt的CMake模块,以及你自己的CMake模块. @note 注意:dtkcore的QMake模块会自动引入Qt5的QMake模块,所以不需要再次引入Qt5的QMake模块,但是在使用CMake的时候必须手动引入Qtcore的CMake模块 ## 文档 阅读文档建议从模块页面开始,模块页面提供了dtkcore的各个模块的简介,以及各个模块的使用示例。 @subpage DLog dtkcore的文档使用doxygen管理,由deepin_doc_doc_go_sig提供维护支持, 如果你也想加入sig,请访问[deepin_doc_doc_go_sig](https://matrix.to/#/#deepin_doc_doc_go:matrix.org) ## 许可 dtkcore使用LGPLv3许可证,你可在此许可证下自由使用dtkcore
dtkcore的文档使用[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)许可证,你可在此许可证下自由使用dtkcore的文档,但是转发或者引用时必须注明出处。 dtkcore-5.7.12/docs/Specification.md000066400000000000000000000046411476226660600173170ustar00rootroot00000000000000# Deepin Application Specification {#Specification} Every application should keep the rule in this document. ## 1. Application Information Application should set the property Organization-name and Application-name. Organization/Application name can contains alphabet, number and other visible ASCII code, BUT space MUST NOT appear in the name. And we do not approve of no-ASCII code character in the Organization/Application name Application can stay Organization-name empty, but it should always set an Application-name. ## 2. Standard Path The log, configure and runtime cache of Application should store in specific path. **If Organization-name is empty, "{Organization-name}/" would not appear in path.** ### 2.1 User Application Standard Path As an application run for user session, the Standard path should be: ````bash XGD_LOG_HOME_DEEPIN: Where deepin-user-specific log should be written. XGD_USER_HOME/.log DAPP_CONFIG_HOME: Where application-specific configurations should be written. XDG_CONFIG_HOME/{Organization-name}/{Application-name} DAPP_LOG_HOME: Where application-specific log should be written. XGD_LOG_HOME_DEEPIN/{Organization-name}/{Application-name} DAPP_CACHE_HOME: Where application-specific cache files should be written. XGD_CACHE_HOME/{Organization-name}/{Application-name} DAPP_DATA_HOME: Where application-specific data files should be written. $XDG_DATA_HOME/{Organization-name}/{Application-name} ```` Simple example: The dde-dock is offcial application of deepin and the standard path will be: ````bash DAPP_CONFIG_HOME: $HOME/.config/deepin/dde-dock DAPP_LOG_HOME: $HOME/.log/deepin/dde-dock DAPP_CACHE_HOME: $HOME/.cache/deepin/dde-dock DAPP_DATA_HOME: $HOME/.local/share/deepin/dde-dock ```` ### 2.2 System Application Standard Path Application run as system daemon, or with user with no home directory should place it's file in this standard path: ````bash DAPP_CONFIG_SYS: /etc/{Organization-name}/{Application-name} DAPP_LOG_SYS: /var/log/{Organization-name}/{Application-name} DAPP_DATA_SYS: /usr/share/{Organization-name}/{Application-name} DAPP_CACHE_SYS: /var/cache/{Organization-name}/{Application-name} ```` Refs: [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.8.html) [XDG Base Directory support](https://wiki.archlinux.org/index.php/XDG_Base_Directory_support) dtkcore-5.7.12/docs/dci/000077500000000000000000000000001476226660600147475ustar00rootroot00000000000000dtkcore-5.7.12/docs/dci/ddcifile.zh_CN.dox000066400000000000000000000117631476226660600202360ustar00rootroot00000000000000/*! @~chinese @file include/dci/ddcifile.h @ingroup dci @class Dtk::Core::DDciFile ddcifile.h @brief ddcifile.h 是关于dci文件相关操作的一个类,实现了 DCI 文件的逻辑。其只是对数据的打包 dci文件的结构路径如下: ![DCI图标结构路径](@ref dciicon-tree.png ) @enum Dtk::Core::DDciFile::FileType @var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::UnknowFile @brief 未知文件 @var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::File @brief 文件 @var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::Directory @brief 目录 @var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::Symlink @brief 软链接 @fn bool Dtk::Core::DDciFile::isValid() @brief 判断读取的dci文件是否有效 @details 当指定的dci文件未成功加载时,此函数会返回false,一般会出现在文件格式错误(不是一个dci格式的文件),或者是dci文件数据被篡改而无法识别的情况 @note 本类中所有涉及文件操作的函数均会首先执行此方法,故如无必要,无需手动确保文件是否有效 @fn QString Dtk::Core::DDciFile::lastErrorString() @brief 获取上一个报错信息,为人类可读字符串,可以通过此报错信息来获取错误内容,一般情况下是因为文件不存在或者文件名过长(>62个字符)导致。 @fn bool Dtk::Core::DDciFile::writeToFile(const QString &fileName) @brief 写入文件,在做完对于dci文件的操作之后调用此接口,为保存的作用 @param[in] fileName 文件名 @fn bool Dtk::Core::DDciFile::writeToDevice(QIODevice *device) @brief 写入到设备,设备指的是qt中的io设备,可以在qt文档中找到相关信息 @param[in] device IO设备 @sa [QIODevice](https://doc.qt.io/qt-6/qiodevice.html) @fn QByteArray Dtk::Core::DDciFile::toData() @brief 返回dci文件的原始数据,以QByteArray形式返回 @retval 如果返回为空字符串则说明读取失败 @sa DDciFile::writeFile @fn static constexpr int Dtk::Core::DDciFile::metadataSizeV1() @brief MAGIC_SIZE + VERSION_SIZE + FILE_COUNT_SIZE: 4+1+3 = 8 @fn QStringList Dtk::Core::DDciFile::list(const QString &dir, bool onlyFileName = false) @brief 列出文件列表 @param[in] dir 文件夹地址 @param[in] onlyFileName 是否只显示文件名 默认为false @fn int Dtk::Core::DDciFile::childrenCount(const QString &dir) @brief 子文件计数 @fn bool Dtk::Core::DDciFile::exists(const QString &filePath) @brief 判断文件是否存在 @param[in] filePath DCI图标结构路径 @fn FileType Dtk::Core::DDciFile::type(const QString &filePath) @brief 判断文件类型 @sa DDciFile::FileType @param[in] filePath DCI图标结构路径 @fn QByteArray Dtk::Core::DDciFile::dataRef(const QString &filePath) @brief 获取dci内部文件的数据,以一种引用(软连接)的方式获取,不会产生数据的的复制 @param[in] filePath DCI图标结构路径 @retval 如果返回为空字符串,则说明此文件不存在或者无效 @fn QString Dtk::Core::DDciFile::name(const QString &filePath) @brief 获取dci内文件的文件名 @param[in] filePath DCI图标结构路径 @retval 如果返回为空字符串,则说明此文件不存在或者无效 @fn QString Dtk::Core::DDciFile::symlinkTarget(const QString &filePath, bool originData = false) @brief 获取软链目标 @param[in] filePath DCI图标结构路径 @param[in] originData @retval 如果返回为空字符串,则说明此文件不存在或者无效 @note 链接的目标只能是“不存在的路径”、“文件”、“链接”,不可是目录 @fn bool Dtk::Core::DDciFile::mkdir(const QString &filePath) @brief 创建目录(注意:此目录指的是在dci文件内部的目录,而不是指的是传统目录) @param[in] filePath DCI图标结构路径 @return 操作是否成功 @fn bool Dtk::Core::DDciFile::writeFile(const QString &filePath, const QByteArray &data, bool override = false) @brief 写入文件 @param[in] filePath DCI图标结构路径 @param[in] data 数据内容 @param[in] override 当文件已经存在时,是否覆盖此文件,默认状态下不执行覆盖,会在lasterror中记录"The target file is existed"错误信息。 如果传入为true,则会执行覆盖操作,** 此操作不可逆 **。 @return 操作是否成功 @sa QByteArray DDciFile::toData() @fn bool Dtk::Core::DDciFile::remove(const QString &filePath) @brief 移除文件 @param[in] filePath DCI图标结构路径 @return 操作是否成功 @fn bool Dtk::Core::DDciFile::rename(const QString &filePath, const QString &newFilePath, bool override = false) @brief 重命名文件 @param[in] filePath DCI图标结构路径 @param[in] newFilePath 新文件的路径 @param[in] override 当文件已经存在时,是否覆盖此文件,默认状态下不执行覆盖,会在lasterror中记录"The target file is existed"错误信息。 如果传入为true,则会执行覆盖操作,** 此操作不可逆 **。 @return 操作是否成功 @fn bool Dtk::Core::DDciFile::link(const QString &source, const QString &to) @brief 链接文件 @param[in] source 文件源 @param[in] to 链接目标 @return 操作是否成功 */ dtkcore-5.7.12/docs/dci/index.zh_CN.md000066400000000000000000000227341476226660600174100ustar00rootroot00000000000000@page dci dci--dci图标工具类 # DTk dci:dci工具类 关于dtkcore提供的dci工具见:[DCI](group__dci.html#files)
下面内容是关于dci文件的简介,还有一部分使用以及工具将会在以后的文档中提供 ## 关于dci图标简介 `DCI` 图标是一种整合性图标格式,应用可以使用该图标完成多种状态的自动变化。例如, `ListView` 控件中高亮的 `Item` 图标自动反白,`Menu` 中图标跟随当前 `Item` 变化等等。 `dtkcore` 中提供了一个 `DDciFile` 的类,实现 `DCI` 文件的逻辑。其只是对数据的打包,不限于图片数据,可以是任何文本和二进制数据。 `dtkcore` 中还提供了用于在文管中解析文件的文件引擎,专门用于通过 `QFile` 和 `QDir` 处理 `dci` 文件。 dtkgui 中提供了一个 `DDciIcon` 类,实现了对 `DCI` 图标的逻辑。区别于 `DDciFile` ,它是 `DDciFile` 的上层封装,即使用 DDciFile 可以将文件进行打包归档的功能,封装了一种图标格式。 `DDciIcon` 中提供的接口,都是针对图标的,并无 `DDciFile` 的数据处理操作,多个 `DDciIcon` 进行数据拷贝和交换时,可以进行数据共享。 `DDciIcon` 可以通过调用 pixmap 函数返回需要显示的图片数据,也可以通过调用 paint 函数直接将内容绘制到目标内部。解析 Dci 图标的过程,这里讲解一下,详细过程可以查看代码理解: 首先需要创建一个 DDciFile 来解析 (*.dci) 文件,无论是本地文本还是二进制数据,都可以通过 `DDciFile` 来解析内部内容。 根据 `DDciIcon` 中规定好的路径格式,来解析出图标中拟定的各种信息,一般情况下的 `DDciIcon` 的路径格式是这样的: ![DCI图标结构路径](@ref dciicon-tree.png ) 最上层时 `/` 作为根目录( `DCI` 文件都必须使用 `/` 作为根目录)。 第一层子目录( 16、32、512 )作为图标的大小。一般情况下是图标在 @1(1倍缩放比) 时的大小(在目前的使用设计师使用的 dci 图标插件的)。例如上述图标,传入的大小在 0-16时选择 16,传入大小在 16-32 时选择 32,... 以此类推。 第二层目录( `normal.light` )作为该层图标的状态和主题,其中状态分为 `Normal` , `Disabled` , `Hovered` 和 `Pressed` 四种,主题分为 `light` 和 `dark` 两种。四种状态和两种主题可产生 8 种组合,也就是说,每种大小的图标最多有八种不同状态和主题的子图标进行切换。需要注意的是:状态和主题存在缺省模式: `normal` 和 `light` 。如果传入的状态和主题在所属大小的子图标下未找到,则选择缺省模式的状态和主题。也就是说,当图标的 `Normal` 和 `light` 状态未找到任何图标时,该图标是无效的。一般情况下,如果图标不会在不同状态和主题下发生过大的样式修改,只修改内部颜色填充时,可以不添加特殊状态的图标,通过修改调色版解决。(后面提及) 第三层目录(1、2)作为缩放比系数,可以存放多个缩放比系数来适配系统的缩放比。例如上述示例:缩放比系数在1和2之间时,选择 2,大于 2 时,选择 2 ,默认情况下选择 1。目前提供的图标中,为了保证尽量减少图标文件的大小,仅保存缩放比为 3 的文件。在软件层面进行缩放。 第四层(1.png)描述图标图片文件(图层)所携带的信息。这些信息中,包含:图层优先级、外边框数值、调色板格式、颜色调整数值、图层格式。可以通过下述文件表 ``` ├── 1.7p.3.png.alpha8 ├── 2.3.webp └── 3.7p.3_0_0_-10_0_0_0_0.png.alpha8 │ │ │ │ │ │ ┕━┳━┙┕━┳━┙ │ │ │ │ │ │ rgba format │ │ │ │ │ │ │ │ │ │ │ └─ lightness (亮度) │ │ │ │ └─ saturation (饱和度) │ │ │ └─ hue (色调) │ │ └─ palette (高亮色3) │ └─ padding (填充间隔) └─ prior (图层) .[padding].. ``` 下面进行一一介绍: * **图层优先级**(`prior`):优先级代表图层的绘制顺序,从 1-n 进行绘制,最底层的图层会被上层图层覆盖。 * **外边框数值**(`padding`):外边框在有阴影效果的图标中充分利用。 `padding` 代表图层外围不被控件大小覆盖的区域。 ![layout](@ref layout.png) 类似控件的布局方式,这里可以之看 `padding` 部分, `padding` 定义四周所有数据,举个例子,如果子图标的大小是 32 (第一层目录的数值),一倍缩放比下,如果该图层的 `padding` 大小时 5,那么该图层的真实图片大小是:[32 + 5 × 2, 32 + 5 × 2] = [42, 42]。但最终, `padding` 区域的大小并不计算在整个图标大小内(仅针对 QML,dtkwidget 不支持)。为了区别其他数据, `padding` 的数值后面使用 `'p'` 进行结尾。例如上述示例:`'7p'` 。 * **调色板格式** :当存在调色板时,就表示该图标的颜色是通过调色板的颜色进行动态变化的,外部修改调色板颜色后,预览效果会随之发生变化。因此该图标有两种特性:1. 可以转换成 alpha8 格式; 2. 可以不需要其他状态,通过调色板变化即可。当无调色板时,该部分的数值为空。调色板格式分为5种:无效(-1)、前景色(0)、背景色(1)、高亮前景色(2)、高亮色(3)。 * **颜色调整数值** :颜色调整只针对有调色板的图层(调色板格式部分数据不为空)时。一旦存在,必须要将其所有的数据写入,例如上述示例。颜色调整数值使用 '_' 进行分割。 每个部分表示:hu、saturation、lightness、red、green、blue、alpha。 * **图层格式** :图层格式可以使用:"png"、"jpg"、"webp"。如果图层存在调色板格式,就意味着可以优化其大小,转化为 alpha8 格式,使用".alpha8" 作为后缀,进行标识,在软件渲染时进行进行复原。 `DCI` 图标的细节介绍在 应用图标,上面主要介绍 `DCI` 图标的整个结构和在 `QML` 中的使用方式。其主要是设计实现了一种特殊格式的文件(.dci),该种格式通过路径,名称和文件数据,打包到同一个文件内,使不同状态、大小、主题的多个图标图片,整合到同一个文件内,在程序内部自动匹配当前状态,选择合适的图标图片。因此,总的来说, `DCI` 图标是对多个图标图片的打包归档。 本文将介绍 `DCI` 图标在 `dtkwidget` 和 `dtkdeclarative` 中的使用,对于一些 `DCI` 图标相关的高级知识(使用方无需过度关心),如 “DDciIconPalette”、“缩放比的适配”以及“图片的格式”等等。 **请注意:** 当使用 `DciIcon` 时,如果您认为控件在某种状态下需要进行图标变色或更换图标而未出现时,可能是由于**设计提供的图标未指定变色所需要的调色板对象(可以理解为图标出错)** 或 **设计认为该种场景下不需要变色(即固定样式图标)**,请及时与设计沟通。 ### 1. 图标状态 大部分控件可以分为 `Normal` 、 `Hovered` 、 `Pressed` 和 `Disabled` 四种状态。这四种状态是每种控件的基础状态。因此将使用这几种状态作为图标的状态分类。 #### 答疑 1. 为什么没有 `Checked` 和 `Inactive` 类似这样的状态? `Checked` 状态属于复合状态,并不属于基础状态。 `Checked` 状态下,可以有 `Hovered` 、 `Pressed` 、 `Normal` 等等状态,相同地, `Unchecked` 状态也会存在一样的情况。因此, `Checked` 状态并不适合作为 `DCI` 图标的状态。对于需要时,可通过控件的 `checked` 状态属性,切换下不同的图标即可。 `Inactive` 状态作为窗口的状态,在 `DTK` 应用都会通过降低透明度的方式实现,而不是作为图标状态。 2. 为什么需要这些状态? 存在这些状态的原因是,为了让应用和开发者更加无感知的使用图标,而无需关心不同状态下进行图标切换的操作。方便设计师一次提供多种状态的图标到一个图标文件中,进行压缩整合。防止出现图标资源较多,占用较大系统内存,同时能够帮助设计师在控件的不同状态下,不仅仅只局限于修改图标颜色这一种功能,也可以通过不同的图标代替,更适合多样化的样式设计。 3. 图标不显示可能是什么原因? 很可能是 webp 格式的支持问题, 查看一下系统中是否安装 `qt5-image-formats-plugins` ,这个包中有对 webp 格式图片格式的支持。 ### 2. 图标大小和缩放比 应用所关心的图标大小是否正常,是否能够适配高缩放比模式等等。 `DCI` 图标中都做到了这些,默认情况下,设计师所提供的图标大小能够满足应用开发的需求,应用只需要主动调用接口指定图标大小即可,例如 `dtkwidget`,中 `DIconButton` 可以使用 `setIconSize` 指定; `QML` 中可以指定 `DciIcon` 控件的 `sourceSize` 或者 `Button` 控件的 `icon.size` 等等。而对于高缩放比的适配, `DTK` 已经全部完成无需应用关心。 @defgroup dci @brief dtkdci图标工具类, 提供对于dci文件的操作方法 @details 详细内容可见 [DCI图标简介](md_docs_dci_index_zh_CN.html#autotoc_md0) dtkcore-5.7.12/docs/filesystem/000077500000000000000000000000001476226660600163745ustar00rootroot00000000000000dtkcore-5.7.12/docs/filesystem/dbasefilewatcher.zh_CN.dox000066400000000000000000000055641476226660600234160ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dbasefilewatcher.h @class Dtk::Core::DBaseFileWatcher @brief DBaseFileWatcher 类提供了一系列接口可供监视文件和目录的变动。 @note 建议使用 DFileWatcher 类,该类是 DBaseFileWatcher 的子类,提供了更多的功能。或者使用DFileWatcherManager类,该类提供了对文件和目录的监视功能。 @warning 该类是一个虚类,不应该被直接使用,而应该使用 DFileWatcher 类或者 DFileWatcherManager 类。 @fn QUrl Dtk::Core::DBaseFileWatcher::fileUrl() @brief 返回文件的统一资源定位符 @sa [QUrl](https://doc.qt.io/qt-5/qurl.html) @fn bool Dtk::Core::DBaseFileWatcher::startWatcher() @brief 开始监视文件变动 @return true 成功 false 失败 @sa DBaseFileWatcher::stopWatcher @fn bool Dtk::Core::DBaseFileWatcher::stopWatcher() @brief 停止监视文件变动 @return true 成功 false 失败 @sa DBaseFileWatcher::startWatcher() @fn bool Dtk::Core::DBaseFileWatcher::restartWatcher() @brief 重启监视文件变动 @return true 成功 false 失败 @sa DBaseFileWatcher::startWatcher() @fn virtual void Dtk::Core::DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled = true) @brief 设置是否对`subfileUrl`目录启用文件监视 @param[in] subfileUrl 设置所针对的 Url @param[in] enabled 是否启用文件变动监视 @fn static bool Dtk::Core::DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, SignalType1 signal, const QUrl &arg1) @brief 发送一个信号表示目标目录`targetUrl`得到了一个`signal`信号,包含参数`arg1`
使用方式如下: @code DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileDeleted, QUrl("bookmark:///bookmarkFile1")); @endcode @return 成功发送返回 true,否则返回 false @fn static bool Dtk::Core::DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType2 signal, const QUrl &arg1, const QUrl &arg2) @brief 发送一个信号表示目标目录`targetUrl`得到了一个`signal`信号,包含参数`arg1`和`arg2`
@details 示例用法: @code DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileMoved, QUrl("bookmark:///bookmarkFile1"), QUrl("bookmark:///NewNameFile1")); @endcode @var Dtk::Core::DBaseFileWatcher::fileDeleted(const QUrl &url) @brief 文件被删除的信号 @var Dtk::Core::DBaseFileWatcher::fileMoved(const QUrl &fromUrl, const QUrl &toUrl) @brief 文件被移动的信号 @var Dtk::Core::DBaseFileWatcher::fileAttributeChanged(const QUrl &url) @brief 文件属性被改变的信号 @var Dtk::Core::DBaseFileWatcher::subfileCreated(const QUrl &url) @brief 子文件被创建的信号 @var Dtk::Core::DBaseFileWatcher::fileClosed(const QUrl &url) @brief 文件被关闭的信号 @var Dtk::Core::DBaseFileWatcher::fileModified(const QUrl &url) @brief 文件被修改的信号 */ dtkcore-5.7.12/docs/filesystem/dcapfile.zh_CN.dox000066400000000000000000000237671476226660600216760ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dcapfile.h @class Dtk::Core::DCapFile @brief 对于文件操作的安全封装, 提供了带有安全管控的文件读取, 相关漏洞见[CWE_22](https://cwe.mitre.org/data/definitions/22.html) @fn explicit Dtk::Core::DCapFile(QObject *parent = nullptr) @brief 默认构造函数, 创建一个文件默认文件对象 @fn Dtk::Core::DCapFile::DCapFile(const QString &name, QObject *parent) @brief 重载的构造函数, 接受传入一个文件名, 并创建一个文件对象 @note 调用此构造函数相当于调用默认构造函数+`DCapFile::setFileName()` @fn void Dtk::Core::DCapFile::setFileName(const QString &name) @brief 传入需要操作的文件名 @fn bool Dtk::Core::DCapFile::exists() const @brief 文件是否存在 @note 此处的存在指当前由setFileName() 指定的文件或者是在构造时指定的文件是否可读可写 @note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 @fn static bool Dtk::Core::DCapFile::exists(const QString &fileName) @brief 文件是否存在 @param[in] fileName 文件名 @note 此处的存在指的是此函数的传入的文件名指向的文件是否可读可写 @fn QString Dtk::Core::DCapFile::readLink() const @brief 读取软连接, 如果软连接指向的文件不允许读写, 则返回空字符串 @note 此方法在Qt版本>=5.13后**废弃** @return 返回软连接指向的文件或者目录的绝对路径 @note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 @sa [readLink](https://doc.qt.io/qt-5/qfile-obsolete.html#readLink-1) @fn QString Dtk::Core::DCapFile::symLinkTarget() const @brief 这是一个重载函数
返回符号链接, 或Windows上的快捷方式指向的文件或目录的绝对路径, 如果该对象不是符号链接, 则返回一个空字符串。 @fn bool Dtk::Core::DCapFile::remove() @brief 如果文件存在则删除文件 @note 此处的存在指当前由setFileName() 指定的文件或者是在构造时指定的文件是否可读可写 @note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 @note 文件需要在删除前被关闭 @fn static bool Dtk::Core::DCapFile::remove(const QString &fileName) @brief 如果文件存在则删除文件 @param[in] fileName 文件名 @note 此处的存在指的是此函数的传入的文件名指向的文件是否可读可写 @note 文件需要在删除前被关闭 @sa DCapFile::remove() @fn bool Dtk::Core::DCapFile::moveToTrash() @brief 如果文件存在则将文件移动至默认回收站(垃圾桶) @note 此处的存在指当前由setFileName() 指定的文件或者是在构造时指定的文件是否可读可写 @note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 @note 此方法仅在Qt版本>=5.15.0后可用 @fn bool Dtk::Core::DCapFile::moveToTrash(const QString &fileName, QString *pathInTrash) @brief 如果传入文件名对应文件存在则将文件移动至指定回收站(垃圾桶) @note 此处的存在指的是此函数的传入的文件名指向的文件是否可读可写 @note 此方法仅在Qt版本>=5.15.0后可用 @param[in] fileName 文件名 @param[in] pathInTrash 回收站路径 @fn bool Dtk::Core::DCapFile::rename(const QString &newName) @brief 如果文件名存在则重命名文件 @param[in] newName 新文件名 @note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 @fn static bool Dtk::Core::DCapFile::rename(const QString &oldName, const QString &newName) @brief 如果文件名存在则重命名文件 @param[in] oldName 旧文件名 @param[in] newName 新文件名 @fn bool Dtk::Core::DCapFile::link(const QString &newName) @brief 创建一个名为newName的链接 @details 该链接指向当前由`setFileName()`指定的文件或者是在构造时指定的文件。链接是什么取决于底层文件系统(无论是Windows上的快捷方式还是Unix上的符号链接)。如果成功, 则返回ture;否则返回false @note 如果是windows系统的newName参数必须有`.lnk`合法后缀才可用 @param[in] newName 新文件名 @fn static bool Dtk::Core::DCapFile::link(const QString &oldname, const QString &newName) @brief 该函数是重载`DCapFile::link()`区别是需要手动传入原始文件名 @sa DCapFile::link(const QString &newName) @fn bool Dtk::Core::DCapFile::copy(const QString &newName) @brief `setFileName()`指定的文件或者是在构造时指定的文件复制一份, 名为newName
如果成功, 则返回ture;否则返回false @note 确保文件在复制之前是关闭的 @note 如果复制的文件是一个符号链接(symlink), 它所指的文件被复制, 而不是链接本身。除了权限 会被复制外, 其他的文件元数据都不会被复制。 @note 如果一个名称为 newName 的文件已经存在, `copy()`将会返回true但是并不会覆盖它 @fn static bool Dtk::Core::DCapFile::copy(const QString &fileName, const QString &newName) @brief 该函数是重载`DCapFile::copy(const QString &newName)`区别是需要手动传入原始文件名 @sa DCapFile::copy(const QString &newName) @fn bool Dtk::Core::DCapFile::open(OpenMode flags) @brief 使用OpenMode模式打开文件, 如果成功返回true;否则返回false
@details 模式如下:
NotOpen = 0x0000,
ReadOnly = 0x0001,
WriteOnly = 0x0002,
ReadWrite = ReadOnly | WriteOnly,
Append = 0x0004,
Truncate = 0x0008,
Text = 0x0010,
Unbuffered = 0x0020,
NewOnly = 0x0040,
ExistingOnly = 0x0080
@note 在只写或读写模式下, 如果相关文件不存在, 该函数将在打开文件之前尝试创建一个新文件 @fn bool Dtk::Core::DCapFile::resize(qint64 sz) @brief 设置文件大小sz(以字节为单位)。如果调整大小成功, 则返回true;否则为false。如果sz大于当前文件, 则新字节将设置为 0;如果sz较小, 则文件将被简单地截断 @note 如果文件不存在, 此函数可能会无效 @fn static bool Dtk::Core::DCapFile::resize(const QString &filename, qint64 sz) @brief 该函数是重载`DCapFile::resize(qint64 sz)`区别是手动指定文件名 @sa DCapFile::resize(qint64 sz) */ /*! @class Dtk::Core::DCapFile @brief 对于文件夹操作的封装 @fn Dtk::Core::DCapDir::DCapDir(const DCapDir &) @brief 拷贝构造函数 构造一个DCapDir对象, 该对象是目录目录的DCapDir对象的副本 @fn Dtk::Core::DCapDir::DCapDir(const QString &path = QString()) @brief 构造指向给定目录路径的DCapDir。如果 path 为空, 则使用程序的工作目录`.` @fn Dtk::Core::DCapDir::DCapDir(const QString &path, const QString &nameFilter, SortFlags sort = SortFlags(Name | IgnoreCase), Filters filter = AllEntries) @brief 构造具有路径路径的DCapDir对象 @details 该 DCapDir 使用nameFilter按名称筛选其条目, 并使用筛选器 按属性筛选其条目。它还使用排序对名称进行排序。
默认名称筛选器是一个空字符串, 它不排除任何内容;默认筛选器是“所有条目”, 这也意味着不排除任何内容。默认排序为“名称|忽略大小写, 即按名称排序, 不区分大小写。 如果path为空字符串, DCapDir 将使用 “.”(当前目录)
如果nameFilter为空字符串, DCapDir 将使用名称筛选器“*”(所有文件) @note 路径不需要存在 @fn void Dtk::Core::DCapDir::setPath(const QString &path) @brief 将目录的路径设置为path。该路径被清除了多余的"."、"... "和多个分隔符。没有检查这个路径的 目录是否真的存在;
路径可以是绝对路径也可以是相对路径, 绝对路径以目录分隔符"/"开始(在Windows下可以选择在前面加一个驱动器号, 例如: C:\)
相对路径以目录名开始, 并指定一个相对于当前目录的路径。一个绝对路径的例子是字符串"/etc/apt", 一个相对路径例子是 "src/1/"
@fn bool Dtk::Core::DCapDir::cd(const QString &dirName) @brief 将DCapDir的目录更改为dirName。 如果新目录存在, 则返回true;否则返回false 请注意, 如果新目录不存在, 则不执行逻辑`cd()`操作 @fn QStringList Dtk::Core::DCapDir::entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const @brief 返回目录中所有文件和目录的名称列表 @details 这些名称根据以前使用`setNameFilters()` 和`setFilter()` 设置的名称和属性筛选器排序, 并根据使用`setSorting() 设置的标志进行排序。
可以使用过滤器和排序参数覆盖属性过滤器和排序规范。 如果目录不可读、不存在或与规范不匹配, 则返回空列表。 @fn QString Dtk::Core::DCapDir::entryList(const QStringList &nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) @brief 重载函数, 返回目录中所有文件和目录的名称列表 @sa entryList(Filters filters = NoFilter, SortFlags sort = NoSort) @fn bool Dtk::Core::DCapDir::mkdir(const QString &dirName) const @brief 创建文件夹 @fn bool Dtk::Core::DCapDir::rmdir(const QString &dirName) const @brief 移除文件夹 @fn bool Dtk::Core::DCapDir::mkpath(const QString &dirPath) @brief 创建目录 @fn bool Dtk::Core::DCapDir::rmpath(const QString &dirPath) @brief 移除目录 @fn bool Dtk::Core::DCapDir::exists() const @brief 文件夹是否存在(如果找到同名文件, 此函数将返回 false) @fn bool Dtk::Core::DCapDir::exists(const QString &name) const @brief 指定文件夹是否存在(如果找到同名文件, 此函数将返回 false) @fn bool Dtk::Core::DCapDir::remove(const QString &fileName) @brief 移除文件夹 @fn bool Dtk::Core::DCapDir::rename(const QString &oldName, const QString &newName) @brief 重命名文件夹 @param[in] oldName 旧文件夹名 @param[in] newName 新文件夹名 */ dtkcore-5.7.12/docs/filesystem/dfilesystemwatcher.zh_CN.dox000066400000000000000000000111151476226660600240150ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dfilesystemwatcher.h @class DFileSystemWatcher @brief 监听文件系统变化的类 @details DFileSystemWatcher监视文件系统对文件的更改和目录,通过观察指定的path列表。
调用addPath()来监视特定的文件或目录。多个path可以使用addPaths()函数添加。现有path可以使用removePath()和removePaths()函数删除。
DFileSystemWatcher检查添加到其中的每个path。具有以下特性的文件添加到DFileSystemWatcher可以使用函数Files()和使用函数directories()创建的目录。
fileChanged()信号在文件被修改时发出,重命名或从磁盘中删除。类似地,directoryChanged()在目录或其内容被修改或移除。
请注意,DFileSystemWatcher只停止监视一次文件,它们被重命名或从磁盘和目录中删除一次,它们已从磁盘中移除。 @note 在运行不支持inotify的Linux内核的系统上,包含被监视路径的文件系统不能被卸载。
默认情况下,Windows CE不支持目录监控,这取决于安装的文件系统驱动程序。
监视文件和目录的行为修改操作会消耗系统资源。这意味着有一个限制进程可以使用的文件和目录的数量同时监控。 @fn DFileSystemWatcher::DFileSystemWatcher(QObject *parent) @brief 构造函数,构造一个新的文件系统监视器对象。 @fn DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent = Q_NULLPTR) @brief 构造函数,构造一个新的文件系统监视器对象,监控指定路径列表。 @param paths 要监听的路径列表 @fn bool DFileSystemWatcher::addPath(const QString &file) @brief 添加要监听的路径 @details 如果path存在,则将path添加到文件系统监视器。如果path不存在或已经存在,则不添加它由文件系统监视程序监视。
如果path指定了一个目录,则调用directoryChanged()信号将在path被修改或从磁盘中删除时发出。否则,当path被修改、重命名或删除。,就会触发fileChanged()信号
如果监视成功,则返回true。
监视故障的原因通常与系统有关,但是可能包括资源不存在、访问失败或总监视数量限制,如果平台有一个。 @note 可能有一个系统依赖的数量限制可以同时监控的文件和目录。
如果达到了这个限制,path将不会被监控,返回false。 @param[in] file 要监听的路径 @sa DFileSystemWatcher::addPaths() @sa DFileSystemWatcher::removePath() @fn QStringList DFileSystemWatcher::addPaths(const QStringList &files) @brief 添加要监听的路径列表 @details 将path中的每个path添加到文件系统监视程序。path如果不存在,或者已经存在,则不添加由文件系统监视程序监视。
如果path指定了一个目录,则调用directoryChanged()信号将在path被修改或从磁盘中删除时触发。否则,当path被修改、重命名或删除。,就会触发fileChanged()信号
返回值是一个无法被监视的路径列表。
监视故障的原因通常与系统有关,但是可能包括资源不存在、访问失败或总监视数量限制,如果平台有一个。
@note 可能有一个系统依赖的数量限制可以同时监控的文件和目录。
如果达到了这个限制,多余的path就不会达到,它们将被添加到返回的QStringList中。 @param[in] files 要监听的路径列表 @sa DFileSystemWatcher::addPath() @sa DFileSystemWatcher::removePaths() @fn bool DFileSystemWatcher::removePath(const QString &file) @brief 移除监听的路径 @details 从文件系统监视程序中删除指定的path。
如果监视成功删除,则返回true。
监视删除失败的原因通常与系统有关,但可能是因为path已经被删除了。 @sa DFileSystemWatcher::removePaths() @sa DFileSystemWatcher::addPath() @fn QStringList DFileSystemWatcher::removePaths(const QStringList &files) @brief 移除监听的路径列表 @details 从文件系统监视程序中删除指定的path。
返回值是一个无法被监视的路径列表。
监视删除失败的原因通常与系统有关,但可能是因为path已经被删除了。 @sa DFileSystemWatcher::removePath() @sa DFileSystemWatcher::addPaths() @fn QStringList DFileSystemWatcher::directories() const @brief 获取监听的目录列表 @sa DFileSystemWatcher::files() @fn QStringList DFileSystemWatcher::files() const @brief 获取监听的文件列表 @sa DFileSystemWatcher::directories() */ dtkcore-5.7.12/docs/filesystem/dfilewarcher.zh_CN.dox000066400000000000000000000032621476226660600225520ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dfilewatcher.h @class DFileWatcher @brief DFileWatcher 类提供了对 DBaseFileWatcher 接口的实现,可供监视文件和目录的变动 @fn DFileWatcher::DFileWatcher(const QString &filepath, QObject *parent = 0) @brief 构造函数 @param filepath 要监视的文件或目录的路径 @param parent 父对象 @fn void DFileWatcher::onFileDeleted(const QString &path, const QString &name) @brief 当文件被删除时触发的信号 @param[in] path 文件所在的目录路径 @param[in] name 文件名 @fn void DFileWatcher::onFileAttributeChanged(const QString &path, const QString &name) @brief 当文件属性发生变化时触发的信号 @param[in] path 文件所在的目录路径 @param[in] name 文件名 @fn void DFileWatcher::onFileMoved(const QString &fromPath, const QString &fromName, const QString &toPath, const QString &toName) @brief 当文件被移动时触发的信号 @param[in] fromPath 文件原来所在的目录路径 @param[in] fromName 文件原来的文件名 @param[in] toPath 文件现在所在的目录路径 @param[in] toName 文件现在的文件名 @fn void DFileWatcher::onFileModified(const QString &path, const QString &name) @brief 当文件被修改时触发的信号 @param[in] path 文件所在的目录路径 @param[in] name 文件名 @fn void DFileWatcher::onFileCreated(const QString &path, const QString &name) @brief 当文件被创建时触发的信号 @param[in] path 文件所在的目录路径 @param[in] name 文件名 @fn void DFileWatcher::onFileClosed(const QString &path, const QString &name) @brief 当文件被关闭时触发的信号 @param[in] path 文件所在的目录路径 */ dtkcore-5.7.12/docs/filesystem/dfilewatchermanager.zh_CN.dox000066400000000000000000000067011476226660600241100ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dfilewatchermanager.h @class DFileWatcherManager @brief DFileWatcherManager 类可以帮助管理一系列 DFileWatcher 文件监视器,并在文件变动时发送信号通知. @details 示例代码: ```cpp #include "dfilewatchermanager" #include #include #include #include DCORE_USE_NAMESPACE int main(int argc, char **argv) { QCoreApplication app(argc, argv); DFileWatcherManager manager; QTemporaryFile tmpfile1; // 创建临时文件1 tmpfile1.open(); QFile file1( tmpfile1.fileName()); QTemporaryFile tmpfile2; // 创建临时文件2 tmpfile2.open(); QFile file2( tmpfile2.fileName()); manager.add(tmpfile1.fileName());// 监控临时文件1 manager.add(tmpfile2.fileName());// 监控临时文件2 QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileModified, &app, [=](const QString value) { qDebug() << "文件发生变动:" << value; }); // 文件发生变动时打印文件路径 QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileDeleted, &app, [=](const QString value) { qDebug() << "文件被删除:" << value; }); file1.open(QIODevice::WriteOnly|QIODevice::Text);// 修改临时文件1 file1.write("test"); file1.close(); file2.open(QIODevice::WriteOnly|QIODevice::Text);// 修改临时文件2 file2.write("test"); file2.close(); qDebug() << manager.watchedFiles();// 打印所有被监控的文件路径 qDebug() << "---------------------------"; app.processEvents();// 处理事件 manager.removeAll();// 移除所有的监控 qDebug() << manager.watchedFiles();// 打印所有被监控的文件路径 return app.exec(); } ``` 上面代码演示了如何使用 DFileWatcherManager 类来监控文件变动和清除文件变动的监控. 具体可以参照源码中的example文件夹中的文件变动监控例子. @fn DFileWatcher* DFileWatcherManager::add(const QString &filePath) @brief 为路径`filePath`创建 DFileWatcher 并将其添加到 DFileWatcherManager 中. @return 被创建并添加到 DFileWatcherManager 的 DFileWatcher @fn void DFileWatcherManager::remove(const QString &filePath) @brief 从 DFileWatcherManager 中移除路径`filePath`对应的 DFileWatcher. @fn void DFileWatcherManager::removeAll() @brief 从 DFileWatcherManager 中移除所有的 DFileWatcher. @fn void DFileWatcherManager::watchedFiles() @brief 获取 DFileWatcherManager 中所有的 DFileWatcher. @var void DFileWatcherManager::fileDeleted(const QString &filePath) @brief 当路径`filePath`对应的文件被删除时发送此信号. @var void DFileWatcherManager::fileAttributeChanged(const QString &filePath) @brief 当路径`filePath`对应的文件属性发生变化时发送此信号. @var void DFileWatcherManager::fileMoved(const QString &fromFilePath, const QString &toFilePath) @brief 当路径`fromFilePath`对应的文件被移动到路径`toFilePath`时发送此信号. @var void DFileWatcherManager::fileClosed(const QString &filePath) @brief 当路径`filePath`对应的文件被关闭时发送此信号. @var void DFileWatcherManager::fileModified(const QString &filePath) @brief 当路径`filePath`对应的文件被修改时发送此信号. @var void DFileWatcherManager::subfileCreated(const QString &filePath) @brief 当路径`filePath`对应的文件夹中有新的子文件被创建时发送此信号. */ dtkcore-5.7.12/docs/filesystem/dstandardpaths.zh_CN.dox000066400000000000000000000051211476226660600231130ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dstandardpaths.h @class DStandardPaths @brief DStandardPaths 类描述了一些标准的文件路径,包括XDG文件路径,locate等 @fn static QString DStandardPaths::writableLocation(QStandardPaths::StandardLocation type) @brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口。此处返回可写路径 @fn static QStringList DStandardPaths::standardLocations (QStandardPaths::StandardLocation type) @brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口。此处返回所有Standardpath @fn static QString DStandardPaths::locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile) @brief 在 type 的标准位置查找名为 fileName 的文件或目录。选项标志允许您指定是否查找文件或目录。默认情况下,此标志设置为 LocateFile。返回找到的第一个文件或目录的绝对路径,否则返回空字符串。 @fn static QStringList DStandardPaths::locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile) @brief 在类型的标准位置中按名称 fileName 查找所有文件或目录。选项标志允许您指定是否查找文件或目录。默认情况下,此标志设置为 LocateFile。返回找到的所有文件的列表。 @fn static QString DStandardPaths::findExecutable(const QString &executableName, const QStringList &paths = QStringList()) @brief 同QStandardPaths::findExecutable, 查找可执行文件 @fn static void DStandardPaths::setMode(DStandardPaths::Mode mode) @brief 同QStandardPaths::setTestModeEnabled, 设置是否是测试模式 @fn static QString DStandardPaths::homePath() @brief 返回家目录 @fn static QString DStandardPaths::homePath(const uint uid) @brief 用uid返回家目录 @fn static QString DStandardPaths::path(DStandardPaths::XDG type) @brief 返回对应的xdg目录 @fn static QString DStandardPaths::path(DStandardPaths::DSG type) @brief 返回对应Dsg目录 @fn static QStringList DStandardPaths::paths(DStandardPaths::DSG type) @brief 返回所有DSG下所有目录 @fn static QString DStandardPaths::filePath(DStandardPaths::XDG type, QString fileName) @brief 用xdg和文件名称拼接,返回文件绝对路径 @fn static QString DStandardPaths::filePath(DStandardPaths::DSG type, QString fileName) @brief 用dsg和文件名称拼接,返回文件绝对路径 */ dtkcore-5.7.12/docs/filesystem/dtrashmanager.zh_CN.dox000066400000000000000000000010541476226660600227300ustar00rootroot00000000000000/*! @~chinese @ingroup dfilesystem @file include/filesystem/dtrashmanager.h @class DTrashManager @brief dtk垃圾管理器提供管理文件回收站的功能。 @details 非常简单的一个类 @fn ststic DTrashManager *DTrashManager::instance() @brief 获取DTrashManager的实例 @fn bool DTrashManager::trashIsEmpty() const @brief 判断回收站是否为空 @fn bool DTrashManager::cleanTrash() @brief 清空回收站 @fn bool DTrashManager::moveToTrash(const QString &filePath, bool followSymlink = false) @brief 将文件移动到回收站 */ dtkcore-5.7.12/docs/filesystem/index.zh_CN.md000066400000000000000000000003001476226660600210160ustar00rootroot00000000000000@page dfilesystem dfilesystem--dtk文件系统操作的封装 # Dlog:dtk日志组件 TODO:添加filesystem组件使用说明 @defgroup dfilesystem @brief dtk文件系统操作的封装 dtkcore-5.7.12/docs/global/000077500000000000000000000000001476226660600154505ustar00rootroot00000000000000dtkcore-5.7.12/docs/global/dconfig.zh_CN.dox000066400000000000000000000335351476226660600206060ustar00rootroot00000000000000/*! @~chinese @file include/global/dconfig.h @ingroup dglobal @class Dtk::Core::DConfigBackend dconfig.h @brief 配置后端的抽象接口。 @details 所有DConfig使用的配置后端都继承此类,用户可以继承此类实现自己的配置后端。 @sa FileBackend @sa DBusBackend @sa QSettingBackend @fn Dtk::Core::DConfigBackend::~DConfigBackend() @brief DConfigBackend析构函数 @sa FileBackend::~FileBackend() @sa DBusBackend::~DBusBackend() @sa QSettingBackend::~QSettingBackend() @fn bool Dtk::Core::DConfigBackend::isValid() const = 0 @brief 判断此后端是否可用 @sa DConfig::isValid() @sa FileBackend::isValid() @sa DBusBackend::isValid() @sa QSettingBackend::isValid() @fn bool Dtk::Core::DConfigBackend::load(const QString &) = 0 @brief 初始化后端 @details appId 管理的配置信息key值,默认为应用程序名称。 @sa FileBackend::load() @sa DBusBackend::load() @sa QSettingBackend::load() @fn QStringList Dtk::Core::DConfigBackend::keyList() = 0 @brief 获得所有可用的配置项名称 @sa DConfig::keyList() @sa FileBackend::keyList() @sa DBusBackend::keyList() @sa QSettingBackend::keyList() @fn QVariant Dtk::Core::DConfigBackend::value(const QString &key, const QVariant &fallback = QVariant()) const = 0 @brief 根据配置项名称获得对应值 @param[in] key 配置项名称 @param[in] fallback 没有获取到配置项值后提供的默认值 @sa DConfig::value() @sa FileBackend::value() @sa DBusBackend::value() @sa QSettingBackend::value() @fn void Dtk::Core::DConfigBackend::setValue(const QString &key, const QVariant &value) = 0 @brief 根据配置项名称设置其值 @param[in] key 配置项名称 @param[in] value 需要更新的值 @sa DConfig::setValue() @sa FileBackend::setValue() @sa DBusBackend::setValue() @sa QSettingBackend::setValue() @fn void Dtk::Core::DConfigBackend::reset(const QString &key) @brief 设置其配置项对应的默认值,此值为经过override机制覆盖后的值,不一定为此配置文件中meta中定义的值。 @param[in] key 配置项名称 @sa DConfig::reset() @sa FileBackend::reset() @sa DBusBackend::reset() @sa QSettingBackend::reset() @fn QString Dtk::Core::DConfigBackend::name() const = 0 @brief 后端配置的唯一标识 @sa FileBackend::name() @sa DBusBackend::name() @sa QSettingBackend::name() @fn bool Dtk::Core::DConfigBackend::isDefaultValue(const QString &key) @brief 检测指定配置项名称对应的值是否为默认值。 @param[in] key 配置项名称 @sa DConfig::isDefaultValue() @sa FileBackend::isDefaultValue() @sa DBusBackend::isDefaultValue() @sa QSettingBackend::isDefaultValue() @class Dtk::Core::QSettingBackend dconfig.h @brief QSetting后端,继承自DConfigBackend抽象接口,并实现了虚函数。 @sa DConfigBackend @fn QSettingBackend Dtk::Core::QSettingBackend::QSettingBackend(DConfigPrivate* o) @brief QSettingBackend构造函数 @class Dtk::Core::DConfigPrivate dconfig.h @brief DConfig的私有实现 @fn DConfigPrivate Dtk::Core::DConfigPrivate::DConfigPrivate() @brief DConfigPrivate构造函数 @fn bool Dtk::Core::DConfigPrivate::invalid() @brief 判断此后端是否可用 @fn DConfigBackend* Dtk::Core::DConfigPrivate::getOrCreateBackend() @brief 创建一个配置后端 @details 默认使用的配置后端会优先根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。若没有配置此环境变量,则根据是否有配置中心提供D-Bus服务来选择配置中心服务还是文件配置后端接口。 @fn DConfigBackend* Dtk::Core::DConfigPrivate::createBackendByEnv() @brief 创建一个配置后端 @details 尝试根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。 @var QString Dtk::Core::DConfigPrivate::appId @brief 配置文件所属的应用Id,为空时默认为本应用Id。 @var QString Dtk::Core::DConfigPrivate::name @brief 配置文件名 @var QString Dtk::Core::DConfigPrivate::subpath @brief 配置文件对应的子目录 @var QScopedPointer Dtk::Core::DConfigPrivate::backend @brief 配置策略后端 @class Dtk::Core::DConfig dconfig.h @brief 配置策略提供的接口类 @details ## 概述 此接口规范定义了开发库所提供的关于配置文件读写的相关接口,如果应用程序所使用的开发库实现了此规范,则程序应当优先使用开发库提供的接口。 项目目录结构如下: ```bash ├── CMakeLists.txt ├── config │ └── example.json └── main.cpp ``` ## CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 project(dconfig-example VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ set(CMAKE_CXX_STANDARD 11) # 指定c++标准 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 set(CMAKE_AUTOMOC ON) # 支持qt moc set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 endif() find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5组件Core find_package(Dtk REQUIRED COMPONENTS Core) # 寻找Dtk组件Core add_executable(${PROJECT_NAME} # 生成可执行文件 main.cpp ) target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 Qt5::Core dtkcore ) # dtk_add_config_meta_files函数,部署一些"meta"的配置。 # 函数定义在dtkcore的cmake目录下 # APPID 应用的ID # FILES 需要部署的文件。 dtk_add_config_meta_files( APPID ${PROJECT_NAME} FILES ./config/example.json ) ``` ## example.json ```json { "magic": "dsg.config.meta", "version": "1.0", "contents": { "canExit": { "value": true, "serial": 0, "flags": ["global"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "private" }, "key1": { "value": "125", "serial": 0, "flags": ["nooverride"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "public" }, "number": { "value": 1, "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "array": { "value": ["value1", "value2"], "serial": 0, "flags": ["global"], "name": "array", "permissions": "readwrite", "visibility": "public" }, "map": { "value": {"key1": "value1", "key2": "value2"}, "serial": 0, "flags": ["global"], "name": "map", "permissions": "readwrite", "visibility": "public" } } } ``` ## main.cpp ```cpp #include #include #include DCORE_USE_NAMESPACE int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 构造DConfig,元数据文件名example,与元数据安装目录的/usr/share/dsg/configs/APPID名(可执行文件名)对应目录/example.json, DConfig config("example"); // 判断是否有效 if (!config.isValid()) { qWarning() << QString("DConfig无效, name:[%1]."). arg(config.name()); return 0; } // 获取所有配置项的key qDebug() << "所有的所有配置项的key:" << config.keyList(); // 获取指定配置项的值,配置项可以是字符串,数组,map容器,布尔值,整型,详见example.json qDebug() << "canExit对应的值:" << config.value("canExit").toBool(); QVariantMap map; for (int i = 0; i < 1; i++) { QVariantMap nestItem; for (int j = 0; j < 1; j++) { nestItem[QString::number(j)] = QString::number(j); } map[QString::number(i)] = nestItem; } QScopedPointer heapConfig; heapConfig.reset(new DConfig("example")); if (!heapConfig->isValid()) { qWarning() << QString("DConfig无效, name:[%1]."). arg(heapConfig->name()); return 0; } // 监听值改变的信号 const bool &oldValue = heapConfig->value("canExit").toBool(); QObject::connect(heapConfig.get(), &DConfig::valueChanged, [oldValue,&heapConfig](const QString &key){ qDebug() << "canExit原来的值:" << oldValue << ", canExit新的值:" << heapConfig->value(key).toBool(); }); // 重置canExit的值 heapConfig->setValue("canExit", !oldValue); return a.exec(); } ``` ## 从源码构建 ```bash mkdir build && cd build # 修改路径前缀为/usr,GNU标准的默认值为/usr/local cmake .. -DCMAKE_INSTALL_PREFIX=/usr make sudo make install ``` 结果如下图 ![example](/docs/src/dconfig_example1.png) @fn DConfig Dtk::Core::DConfig(const QString &name, const QString &subpath, QObject *parent) @brief 构造配置策略提供的对象 @param[in] name 配置文件名 @param[in] subpath 配置文件对应的子目录 @param[in] parent 父对象 @fn DConfig Dtk::Core::DConfig(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) @brief 使用自定义的配置策略后端构造对象 @param[in] backend 调用者继承于DConfigBackend的配置策略后端 @param[in] name 配置文件名 @param[in] subpath 配置文件对应的子目录 @param[in] parent 父对象 @fn static DConfig* Dtk::Core::DConfig::create(const QString &appId, const QString &name, const QString &subpath, QObject *parent) @brief 构造配置策略提供的对象,指定配置所属的应用Id,管理某一特定应用的配置。 @param[in] appId 配置文件所属的应用Id,为空时默认为本应用Id @param[in] name 配置文件名 @param[in] subpath 配置文件对应的子目录 @param[in] parent 父对象 @return 构造的配置策略对象,由调用者释放 @fn static DConfig* Dtk::Core::DConfig::create(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) @brief 构造配置策略提供的对象,指定配置所属的应用Id。 @param[in] backend 调用者继承于DConfigBackend的配置策略后端 @param[in] appId 配置文件所属的应用Id,为空时默认为本应用Id @param[in] name 配置文件名 @param[in] subpath 配置文件对应的子目录 @param[in] parent 父对象 @return 构造的配置策略对象,由调用者释放 @fn static DConfig* Dtk::Core::DConfig::createGeneric(const QString &name, const QString &subpath, QObject *parent) @brief 构造配置策略提供的对象,用来管理与应用无关的配置。 @param[in] name 配置文件名 @param[in] subpath 配置文件对应的子目录 @param[in] parent 父对象 @return 构造的配置策略对象,由调用者释放 @note 如果我们管理针对某一特定应用的配置,应该使用 Dtk::Core::DConfig::create(),或 Dtk::Core::DConfig(),来指定所属应用的appId。 @fn static DConfig* Dtk::Core::DConfig::createGeneric(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) @sa Dtk::Core::DConfig::createGeneric() @fn DConfig Dtk::Core::DConfig(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) @brief 使用自定义的配置策略后端构造对象 @param[in] backend 调用者继承于DConfigBackend的配置策略后端 @param[in] appId 配置文件所属的应用Id,为空时默认为本应用Id @param[in] name 配置文件名 @param[in] subpath 配置文件对应的子目录 @param[in] parent 父对象 @note 调用者只构造backend,由DConfig释放。 @fn static void DConfig::setAppId(const QString &appId) @brief 显示指定应用Id,不采用DSGApplication::id()作为应用Id @param[in] appId 配置文件所属的应用Id @note 需要在QCoreApplication构造前设置。 @fn static void DConfig::globalThread() @brief 一个服务于 DConfig 的公用线程,一般用于 dconfig2cpp 生成的代码,此线程在构造时会自动调用 QThread::start 以满足 dconfig2cpp 的需求。 @return 此线程默认为 running 状态 @note 请不要析构它,它会在应用程序退出时释放 @fn QString Dtk::Core::DConfig::backendName() @brief 配置策略后端名称 @return 配置策略后端名称 @note 调用者只能用DConfig访问DConfigBackend对象,所以不返回DConfigBackend对象。 @fn QStringList Dtk::Core::DConfig::keyList() @brief 获得所有可用的配置项名称 @return 配置项名称集合 @fn bool Dtk::Core::DConfig::isValid() @brief 判断此后端是否可用 @fn bool Dtk::Core::DConfig::isDefaultValue(const QString &key) @brief 检测指定配置项名称对应的值是否为默认值。 @param[in] key 配置项名称 @fn QVariant Dtk::Core::DConfig::value(const QString &key, const QVariant &fallback) @brief 根据配置项名称获得对应值 @param[in] key 配置项名称 @param[in] fallback 没有获取到配置项值后提供的默认值 @fn void Dtk::Core::DConfig::setValue(const QString &key, const QVariant &value); @brief 根据配置项名称设置其值 @param[in] key 配置项名称 @param[in] value 需要更新的值 @fn void Dtk::Core::DConfig::reset(const QString &key) @brief 设置其配置项对应的默认值,此值为经过override机制覆盖后的值,不一定为此配置文件中meta中定义的值 @param[in] key 配置项名称 @fn QString Dtk::Core::DConfig::name() @brief 返回配置文件名称 @fn QString Dtk::Core::DConfig::subpath() @brief 返回配置文件对应的子目录 */ dtkcore-5.7.12/docs/global/dconfigfile.zh_CN.dox000066400000000000000000000410661476226660600214440ustar00rootroot00000000000000/*! @~chinese @file include/global/dconfigfile.h @ingroup dglobal @class Dtk::Core::DConfigFile dconfigfile.h @brief 规范配置文件读写的相关接口的配置文件实现 @details ## 概述 规范配置文件读写的相关接口的配置文件实现 项目目录结构如下: ```bash ├── CMakeLists.txt ├── config │ └── example.json └── main.cpp ``` ## CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 project(dconfigfile-example VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ set(CMAKE_CXX_STANDARD 11) # 指定c++标准 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 set(CMAKE_AUTOMOC ON) # 支持qt moc set(CMAKE_AUTORCC ON) # 支持qt资源文件 set(CMAKE_AUTOUIC ON) # 支持qt ui文件(非必须) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 endif() find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5组件Core find_package(Dtk REQUIRED COMPONENTS Core) # 寻找Dtk组件Core add_executable(${PROJECT_NAME} # 生成可执行文件 main.cpp ) target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 Qt5::Core dtkcore ) # dtk_add_config_meta_files函数,部署一些"meta"的配置。 # 函数定义在dtkcore的cmake目录下 # APPID 应用的ID # FILES 需要部署的文件。 dtk_add_config_meta_files( APPID ${PROJECT_NAME} FILES ./config/example.json ) ``` ## example.json ```json { "magic": "dsg.config.meta", "version": "1.0", "contents": { "canExit": { "value": true, "serial": 0, "flags": ["global"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "private" }, "key1": { "value": "125", "serial": 0, "flags": ["nooverride"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "public" }, "number": { "value": 1, "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "array": { "value": ["value1", "value2"], "serial": 0, "flags": ["global"], "name": "array", "permissions": "readwrite", "visibility": "public" }, "map": { "value": {"key1": "value1", "key2": "value2"}, "serial": 0, "flags": ["nooverride"], "name": "map", "permissions": "readwrite", "visibility": "public" }, "publicConfig": { "value": true, "serial": 0, "flags": ["user-public"], "name": "public configure", "name[zh_CN]": "我是公开的配置", "description": "I am public configure", "permissions": "readwrite", "visibility": "private" } } } ``` ## main.cpp ```cpp #include #include #include #include DCORE_USE_NAMESPACE int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 构造DConfigFile,元数据文件名example,与元数据安装目录的/usr/share/dsg/configs/APPID名(可执行文件名)对应目录/example.json, DConfigFile configFile("dconfigfile-example","example"); // 解析配置文件 configFile.load(); // 创建用户缓存 QScopedPointer userCache(configFile.createUserCache(getuid())); // 解析配置文件 userCache->load(); // 判断是否有效 if (!configFile.isValid()) { qWarning() << QString("DConfig无效."); return 0; } // meta 返回原型对象, keyList获取所有配置项的key qDebug() << "所有的所有配置项的key:" << configFile.meta()->keyList(); // 获取指定配置项的值,配置项可以是字符串,数组,map容器,布尔值,整型,详见example.json qDebug() << "canExit对应的值:" << configFile.value("canExit").toBool(); // 配置项的可见性,其余配置项标记、配置项的权限可查看文档 qDebug() << "配置项的可见性" << configFile.meta()->visibility("canExit"); QVariantMap map; map.insert("k1","v1"); map.insert("k2","v2"); // 设置map的值 configFile.setValue("map", map, "dconfigfile-example", userCache.get()); configFile.save(); // root用户运行,save的数据会保存到/root/.config/dsg/configs-fake-global/dconfigfile-example/example.json // map数据对应的flags标记为NoOverride,配置项允许被覆盖,如果flags为global泽忽略用户身份,详见文档。 userCache->save(); return a.exec(); } ``` ## 从源码构建 ```bash mkdir build && cd build # 修改路径前缀为/usr,GNU标准的默认值为/usr/local cmake .. -DCMAKE_INSTALL_PREFIX=/usr sudo make install sudo ./dconfigfile-example ``` 结果如下图 ![一些简单的输出](/docs/src/dconfigfile_example1.png) ![用户保存的数据](/docs/src/dconfigfile_example2.png) @enum Dtk::Core::DConfigFile::Flag @brief 配置项名称 @var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::NoOverride @brief 存在此标记时,将表明则此配置项不可被覆盖(详见下述 override 机制)。反之,不存在此标记时表明此配置项允许被覆盖,对于此类配置项,如若其有界面设置入口,则当此项不可写时,应当隐藏或禁用界面的设置入口. @var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::Global @brief 当读写此类配置时,将忽略用户身份,无论程序使用哪个用户身份执行,读操作都将获取到同样的数据,写操作将对所有用户都生效。但是,如果对应的配置存储目录不存在或无权限写入,则忽略此标志 @var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::UserPublic @brief 该类配置项允许被其他用户访问 @enum Dtk::Core::DConfigFile::Permissions @brief 配置项的权限 @var Dtk::Core::DConfigFile::Permissions Dtk::Core::DConfigFile::ReadOnly @brief 将配置项覆盖为只读 @var Dtk::Core::DConfigFile::Permissions Dtk::Core::DConfigFile::ReadWrite @brief 将配置项覆盖为可读可写 @enum Dtk::Core::DConfigFile::Visibility @brief 配置项的可见性 @var Dtk::Core::DConfigFile::Visibility Dtk::Core::DConfigFile::Private @brief 仅限程序内部使用,对外不可见。此类配置项完全由程序自己读写,可随意增删改写其含义,无需做兼容性考虑 @var Dtk::Core::DConfigFile::Visibility Dtk::Core::DConfigFile::Public @brief 外部程序可使用。 此类配置项一旦发布,在兼容性版本的升级中,要保障此配置项向下兼容,简而言之,只允许在程序/库的大版本升级时才允许删除或修改此类配置项,当配置项的 permissions、visibility、flags 任意一个属性被修改则认为此配置项被修改,除此之外修改 value、name、description 属性时则不需要考虑兼容性。 @struct Dtk::Core::DConfigFile::Version @brief 版本信息 @details 此文件的内容格式的版本。版本号使用两位数字描述, 首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。 读取此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,忽略此文件, 并在程序日志中写入警告信息,如 “1.0” 和 “2.0” 版本之间不兼容, 如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该终止解析, 但是如果遇到 1.1 版本,则可以继续执行。 写入此描述文件时,遇到不兼容的版本时,需要先清空当前内容再写入,每次写入皆需更新此字段。 @fn static constexpr DConfigFile::Version Dtk::Core::DConfigFile::supportedVersion() @brief 支持的版本 @return @fn Dtk::Core::DConfigFile::DConfigFile(const QString &appId, const QString &name, const QString &subpath = QString()) @brief DConfigFile构造函数,构造配置文件管理对象。 @param[in] appId 应用程序唯一标识 @param[in] name 配置文件名 @param[in] subpath 子目录 @fn Dtk::Core::DConfigFile::DConfigFile(const DConfigFile &other); @brief DConfigFile构造函数,构造配置文件管理对象。 @param[in] appId 应用程序唯一标识 @param[in] name 配置文件名 @param[in] subpath 子目录 @fn bool Dtk::Core::DConfigFile::load(const QString &localPrefix = QString()) @brief 解析配置文件 @param[in] localPrefix 为目录前缀 @return @fn bool Dtk::Core::DConfigFile::load(QIODevice *meta, const QList &overrides) @brief 解析配置文件流 @param[in] meta 为原型流 @param[in] overrides 为覆盖机制查找的文件流 @return @fn bool Dtk::Core::DConfigFile::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) const @brief 保存缓存的值到磁盘中 @param[in] format 保存格式 @param[in] sync 是否立即刷新 @return @fn bool Dtk::Core::DConfigFile::isValid() const @brief 检测配置文件是否有效 @return @fn QVariant Dtk::Core::DConfigFile::value(const QString &key, DConfigCache *userCache = nullptr) const @brief DConfigFile::value @param[in] key 配置项名称 @param[in] userCache 用户缓存,当key为全局项时, \a userCache 不会被使用 @return @fn QVariant Dtk::Core::DConfigFile::cacheValue(DConfigCache *userCache, const QString &key) const @brief DConfigFile::cacheValue 获取指定用户缓存的配置项值,若无此配置项的用户缓存值,返回无效值 @param[in] key 配置项名称 @param[in] userCache 用户缓存,当key为全局配置项时, \a userCache 不会被使用 @return @fn bool Dtk::Core::DConfigFile::setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache = nullptr) @brief 设置缓存中的值 @param[in] key 配置项名称 @param[in] value 需要设置的值 @param[in] uid 设置时的用户id @param[in] appid 设置时的应用id @return 为true时表示重新设置了新值,false表示没有设置 @fn DConfigCache* Dtk::Core::DConfigFile::createUserCache(const uint uid) @brief 创建用户缓存 @fn DConfigCache* Dtk::Core::DConfigFile::globalCache() const @brief 返回全局缓存 @return @fn DConfigMeta* Dtk::Core::DConfigFile::meta() @brief 返回原型对象 @return */ /*! @class Dtk::Core::DConfigMeta dconfigfile.h @brief 提供配置文件的原型和覆盖机制的访问接口 @fn virtual DConfigFile::Version Dtk::Core::DConfigMeta::version() const = 0 @brief 返回配置版本信息 @return @fn virtual void Dtk::Core::DConfigMeta::setVersion(quint16 major, quint16 minor) = 0 @brief 设置配置版本信息 @param[in] major 主板本号 @param[in] minor 次版本号 @fn virtual bool Dtk::Core::DConfigMeta::load(const QString &localPrefix = QString()) = 0 @brief 解析配置文件 @param[in] localPrefix 为目录前缀 @return @fn virtual bool Dtk::Core::DConfigMeta::load(QIODevice *meta, const QList &overrides) = 0 @brief 解析配置文件流 @param[in] meta 为原型流 @param[in] overrides 为覆盖机制查找的文件流 @return @fn virtual QStringList Dtk::Core::DConfigMeta::keyList() const = 0 @brief 返回配置内容的所有配置项 @return @fn virtual DConfigFile::Flags Dtk::Core::DConfigMeta::flags(const QString &key) const = 0 @brief 返回指定配置项的特性 @param[in] key 配置项名称, NoOverride为此配置项不可被覆盖, Global为忽略用户身份 @return @fn virtual DConfigFile::Permissions Dtk::Core::DConfigMeta::permissions(const QString &key) const = 0 @brief 返回指定配置项的权限 @param[in] key 配置项名称 @return @fn virtual DConfigFile::Visibility Dtk::Core::DConfigMeta::visibility(const QString &key) const = 0 @brief 返回指定配置项的可见性 @param[in] key 配置项名称 @return @fn virtual int Dtk::Core::DConfigMeta::serial(const QString &key) const = 0 @brief 返回配置项的单调递增值 @param[in] key 配置项名称 @return -1为无效值,表明没有配置此项 @fn virtual QString Dtk::Core::DConfigMeta::displayName(const QString &key, const QLocale &locale) = 0 @brief 返回指定配置项的显示名 @param[in] key 配置项名称 @param[in] locale 为语言版本 @return @fn virtual QString Dtk::Core::DConfigMeta::description(const QString &key, const QLocale &locale) = 0 @brief 返回指定配置项的描述信息 @param[in] key 配置项名称 @param[in] locale 为语言版本 @return @fn virtual QString Dtk::Core::DConfigMeta::metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0 @brief 返回描述文件的路径 @param[in] localPrefix 目录的所有需要查找的覆盖机制目录 @param[in] useAppId 是否不使用通用目录 @return @fn virtual QStringList Dtk::Core::DConfigMeta::allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0 @brief 获得前缀为 `prefix` 目录的所有需要查找的覆盖机制目录 @param[in] useAppId 是否不使用通用目录 @param[in] prefix 目录的应用或公共库的所有覆盖机制目录 @return @fn virtual QVariant DConfigMeta::value(const QString &key) const = 0 @brief meta初始值经过覆盖机制覆盖后的原始值 @param[in] key 配置项名称 @return @fn static QStringList genericMetaDirs(const QString &localPrefix = QString()) @brief 获取应用无关配置存储的目录 @param[in] localPrefix 配置的目录前缀 @return 返回应用无关配置存储的目录列表 @fn static QStringList applicationMetaDirs(const QString &localPrefix, const QString &appId) @brief 获取应用配置存储的目录 @param[in] localPrefix 配置的目录前缀 @param[in] appId 应用唯一标识 @return 返回存储应用配置的目录列表 */ /*! @class Dtk::Core::DConfigCache dconfigfile.h @brief 提供配置文件的用户和全局运行缓存访问接口 @fn virtual bool Dtk::Core::DConfigCache::load(const QString &localPrefix = QString()) = 0 @brief 解析缓存配置文件 @return @fn virtual bool Dtk::Core::DConfigCache::load(const QString &localPrefix = QString()) = 0 @brief 解析缓存配置文件 @return @fn virtual bool Dtk::Core::DConfigCache::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0 @brief 保存缓存的值到磁盘中 @param[in] localPrefix 为目录前缀 @param[in] format 保存格式 @param[in] sync 是否立即刷新 @return @fn virtual bool Dtk::Core::DConfigCache::isGlobal() const = 0 @brief 是否是全局缓存 @return @fn virtual void Dtk::Core::DConfigCache::remove(const QString &key) = 0 @brief 删除缓存中的配置项 @param[in] key 配置项名称 @return @fn virtual QStringList Dtk::Core::DConfigCache::keyList() const = 0 @brief 返回配置内容的所有配置项 @return @fn virtual bool Dtk::Core::DConfigCache::setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &callerAppid) = 0 @brief 设置缓存中的值 @param[in] key 配置项名称 @param[in] value 需要设置的值 @param[in] uid 设置时的用户id @param[in] callerAppid 设置时的应用id @return 为true时表示重新设置了新值,false表示没有设置。 @fn virtual QVariant Dtk::Core::DConfigCache::value(const QString &key) const = 0 @brief 获取缓存中的值 @param[in] key 配置项名称 @return @fn virtual int Dtk::Core::DConfigCache::serial(const QString &key) const = 0 @brief 返回配置项的单调递增值 @param[in] key 配置项名称 @return -1为无效值,表明没有配置此项 @fn virtual uint Dtk::Core::DConfigCache::uid() const = 0 @brief 用户标识,为全局缓存时,uid为非用户标识的特定值 @return @fn virtual void setCachePathPrefix(const QString &prefix) = 0 @brief 指定缓存位置前缀,缓存访问所需的权限及区分不同缓存的位置由调用者考虑,其默认值参考配置策略规范 @param[in] prefix 缓存位置的前缀 */ dtkcore-5.7.12/docs/global/ddesktopentry.zh_CN.dox000066400000000000000000000410631476226660600220670ustar00rootroot00000000000000/*! @~chinese @file include/global/ddesktopentry.h @ingroup dglobal @class Dtk::Core::DDesktopEntry ddesktopentry.h @brief 处理desktop文件的接口 @details ## 概述 DDesktopEntry提供了处理XDG desktop读写的方法的接口,这个Class类似于QSettings。 有关该规范本身的更多详细信息,请参阅: https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html 项目目录结构在同一目录下 ## CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 project(example1 VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ set(CMAKE_CXX_STANDARD 11) # 指定c++标准 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 set(target example1) # 指定目标名称 set(CMAKE_AUTOMOC ON) # support qt moc # 支持qt moc set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 set(CMAKE_AUTOUIC ON) # support qt ui file # 支持qt ui文件(非必须) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # support clangd # 支持 clangd if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 endif() find_package(Qt5 COMPONENTS Core REQUIRED) # 寻找Qt5组件Core find_package(Dtk COMPONENTS Core REQUIRED) # 寻找Dtk组件Core add_executable(${target} # 生成可执行文件 main.cpp ) target_link_libraries(${target} PRIVATE # 添加需要链接的共享库 Qt5::Core dtkcore ) ``` ## main.cpp ```cpp #include #include #include #include DCORE_USE_NAMESPACE // 使用Dtk Core命名空间 const QString fileContent = { QStringLiteral(R"desktop(# A. Example Desktop Entry File [Desktop Entry] Version=1.0 Type=Application Name=Foo Viewer Name[zh_CN]=福查看器 Comment=The best viewer for Foo objects available! # Next line have an extra " character Comment[zh_CN]=最棒的 "福 查看器! TryExec=fooview Exec=fooview %F Icon=fooview MimeType=image/x-foo; Actions=Gallery;Create; [Desktop Action Gallery] Exec=fooview --gallery Name=Browse Gallery [Desktop Action Create] Exec=fooview --create-new Name=Create a new Foo! Icon=fooview-new )desktop") }; int main(int argc, char *argv[]) { QFile file("example1.desktop"); // 尝试打开文件 if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){ qDebug()<<"文件打开失败"; } const QString fileName = file.fileName(); QTextStream ts(&file); ts << fileContent; file.close(); QFile::exists(fileName); // 打开一个fileName为example1.desktop的文件 QScopedPointer desktopFile(new DDesktopEntry(fileName)); // 获取desktop中所有组并返回列表,对应"Desktop Entry"、"Desktop Action Gallery"、"Desktop Action Create"三组 QStringList allGroups = desktopFile->allGroups(); qDebug() << QString("Desktop 文件共有%1组").arg(allGroups.count()); // 调用allGroups函数,传入true,保持读取desktop文件时的顺序不变,获取第0组 qDebug() << QString("Desktop 文件第0组为: %1").arg(desktopFile->allGroups(true)[0]); // 获取key=Name,localeKey=zh_CN的值,即Name[zh_CN]=福查看器 qDebug() << QString("Name[zh_CN]=%1") \ .arg(desktopFile->localizedValue("Name", "zh_CN")); // 获取key为Nam,,localeKey为empty的值,empty表示没有localeKey,即Name=Foo Viewer qDebug() << QString("Name=%1") \ .arg(desktopFile->localizedValue("Name", "empty")); // 获取Desktop Entry组下的所有key,即"Actions", "Comment", "Comment[zh_CN]", "Exec", "Icon", "MimeType", "Name", "Name[zh_CN]", "TryExec", "Type", "Version" qDebug() << QString("Desktop Entry组下的所有key: ") \ << desktopFile->keys("Desktop Entry"); // 设置 key 为 Name的值为"Bar Viewer",默认组是"Desktop Entry" desktopFile->setRawValue("Bar Viewer", "Name"); // 设置 key 为 Name,localeKey为zh_CN的值为霸查看器,默认组是"Desktop Entry" desktopFile->setLocalizedValue("霸查看器", "zh_CN", "Name"); // 检查 section 中是否包 key 为 Semicolon 的值,包含 key 返回true; 否则返回false,默认组是Desktop Entry qDebug() << QString("Desktop Entry组是否包key是Semicolon: ") \ << desktopFile->contains("Semicolon", "Desktop Entry"); // 设置key为Semicolon的值为";grp\\;2;grp3;",默认组是"Desktop Entry" desktopFile->setRawValue(";grp\\;2;grp3;", "Semicolon"); // 返回给定 section 中与给定 key 关联的字符串的列表。如果destkop不包含为该键的项,则函数返回一个空字符串列表。 默认组是Desktop Entry qDebug() << QString("Desktop Entry组中Semicolon对应值的字符串列表: ") \ << desktopFile->stringListValue("Semicolon"); // 再次检查 section 中是否包 key 为 Semicolon 的值,此时为true qDebug() << QString("Desktop Entry组是否包key是Semicolon: ") \ << desktopFile->contains("Semicolon", "Desktop Entry"); // 删除desktop中 section 中 key 对应的值,默认组是"Desktop Entry" desktopFile->removeEntry("Semicolon", "Desktop Entry"); // 再次检查 section 中是否包 key 为 Semicolon 的值,此时为false qDebug() << QString("Desktop Entry组是否包key是Semicolon: ") \ << desktopFile->contains("Semicolon", "Desktop Entry"); // 将数据回写到desktop文件。 true表示写成功; 否则返回false if (desktopFile->save()) { qDebug() << "文件保存成功"; } else { qDebug() << "文件保存失败"; } return 0; } ``` 结果如下图 ![example](/docs/src/ddesktopentry_example1.png) @enum Dtk::Core::DDesktopEntry::EntryType @brief 桌面入口文件的类型 @var Dtk::Core::DDesktopEntry::Unknown @brief 未知的桌面文件类型。可能是无效的 @var Dtk::Core::DDesktopEntry::Application @brief 该文件描述应用程序 @var Dtk::Core::DDesktopEntry::Link @brief 该文件描述URL @var Dtk::Core::DDesktopEntry::Directory @brief 该文件描述目录设置 @var Dtk::Core::DDesktopEntry::ServiceType @brief KDE特定类型。规范中提到过, 所以这里也列出了 @var Dtk::Core::DDesktopEntry::Service @brief KDE特定类型。规范中提到过, 所以这里也列出了 @var Dtk::Core::DDesktopEntry::FSDevice @brief KDE特定类型。规范中提到过, 所以这里也列出了 @enum Dtk::Core::DDesktopEntry::ValueType @brief 值的类型 @var Dtk::Core::DDesktopEntry::Unparsed @brief 未解析的值 @var Dtk::Core::DDesktopEntry::String @brief 字符串 @var Dtk::Core::DDesktopEntry::Strings @brief 字符串数组 @var Dtk::Core::DDesktopEntry::Boolean @brief 布尔值 @var Dtk::Core::DDesktopEntry::Numeric @brief 数字 @var Dtk::Core::DDesktopEntry::NotExisted @brief 不存在 @enum Dtk::Core::DDesktopEntry::Status @brief desktop文件的解析状态 @var Dtk::Core::DDesktopEntry::NoError @brief 没有错误发生 @var Dtk::Core::DDesktopEntry::AccessError @brief 发生访问错误(例如, 试图写入只读文件) @var Dtk::Core::DDesktopEntry::FormatError @brief 发生格式错误(例如, 加载格式错误的desktop文件) @fn Dtk::Core::DDesktopEntry::DDesktopEntry(const QString &filePath) noexcept @brief DDesktopEntry构造函数 @fn bool Dtk::Core::DDesktopEntry::save() const @brief 将数据回写到desktop文件。 @return true表示写成功; 否则返回false @fn Status Dtk::Core::DDesktopEntry::status() const @brief Get data parse status @return 返回一个状态码, 表示DDesktopEntry遇到的第一个错误, 如果没有错误发生, 则返回QSettings::NoError。请注意, DDesktopEntry会延迟执行某些操作。 @fn QStringList Dtk::Core::DDesktopEntry::keys(const QString §ion = "Desktop Entry") const @brief 根据 `section` 返回全部键值 @return 返回所有的键值 @fn QStringList Dtk::Core::DDesktopEntry::allGroups(bool sorted = false) const @brief 获取desktop中所有组的列表。如果 `sorted` 设置为true, 则返回结果将保持读取desktop文件时的顺序不变。 @return 返回所有的组. @fn bool Dtk::Core::DDesktopEntry::contains(const QString &key, const QString §ion = "Desktop Entry") const @brief 检查desktop文件是否有给定的 `section` 包含给定的 `key` @return 如果desktop在 `section` 包含 `key` 返回true; 否则返回false。 @fn QString Dtk::Core::DDesktopEntry::name() const @brief 返回“Desktop Entry”部分下的“Name”键的本地化字符串值。这等价于调用localizedValue("Name")。 @return 返回“Desktop Entry”部分下的“Name”键的本地化字符串值。 @sa localizedValue(), genericName(), ddeDisplayName() @fn QString Dtk::Core::DDesktopEntry::genericName() const @brief 返回"Desktop Entry"部分下的"GenericName"键的本地化字符串值。它等价于调用localizedValue("GenericName")。如果是“GenericName”不存在。则不会回退到“Name”。 @return 返回"Desktop Entry"部分下的"GenericName"键的本地化字符串值。 @sa localizedValue(), name(), ddeDisplayName() @fn QString Dtk::Core::DDesktopEntry::ddeDisplayName() const @brief 为DDE应用程序专门显示名称 @details 这将检查“X-Deepin-Vendor”,并将返回本地化的字符串值“GenericName” "X-Deepin-Vendor"是"deepin",否则它将返回"Name"的本地化字符串值。 @return 返回专门用于DDE应用程序的显示名称 @sa localizedValue(), name(), genericName() @fn QString Dtk::Core::DDesktopEntry::comment() const @brief 返回“Desktop Entry”部分下的“Comment”键的本地化字符串值。这等价于调用localizedValue("Comment")。 @return 返回“Desktop Entry”部分下的“Comment”键的本地化字符串值。 @sa localizedValue() @fn QString Dtk::Core::DDesktopEntry::rawValue(const QString &key, const QString §ion = "Desktop Entry", const QString &defaultValue = QString()) const @brief 返回 `section` 中与给定 `key` 关联的原始字符串值。如果desktop不包含具有该键的项, 则函数返回一个构造好的 `defaultValue`。 @return 返回 `section` 中与给定 `key` 相关联的原始字符串值。 @sa stringValue() localizedValue() stringListValue() @fn QString Dtk::Core::DDesktopEntry::stringValue(const QString &key, const QString §ion = "Desktop Entry", const QString &defaultValue = QString()) const @brief 返回 `section` 与给定 `key` 关联的未转义字符串值。如果desktop不包含键值为0的项, 则函数返回一个构造好的 `defaultValue`。 @return 返回 `section` 中与给定 `key` 相关联的未转义字符串值。 @sa rawValue() localizedValue() stringListValue() @fn QString Dtk::Core::DDesktopEntry::localizedValue(const QString &key, const QString &localeKey = "default", const QString §ion = "Desktop Entry", const QString& defaultValue = QString()) const @brief 返回与 `section` 中给定的 `key` 和 `localeKey` 相关联的本地化字符串值。 @details 如果找不到给定的 `localeKey` ,它将回退到"C",如果仍然找不到,将回退 `key` 没有`localeKey`部分。。 如果destkop不包含 `key` 值为0的项,则函数返回一个构造好的 `defaultValue`。 @return 返回 `section` 中与给定的 `key` 和 `localeKey` 关联的本地化字符串值。 @sa rawValue() stringValue() stringListValue() @fn QString Dtk::Core::DDesktopEntry::localizedValue(const QString &key, const QLocale &locale, const QString §ion = "Desktop Entry", const QString& defaultValue = QString()) const @brief 返回与给定的 `key` 和 `section` 中的区域设置相关联的本地化字符串值。 @details 如果找不到给定的 `localeKey` ,它将回退到"C",如果仍然找不到,将回退 `key` 没有`localeKey`部分。 如果destkop不包含 `key` 值为0的项,则函数返回一个构造好的 `defaultValue`。 @return 返回 `section`中 与给定的 `key` 和 `locale` 设置相关联的本地化字符串值。 @sa rawValue() stringValue() stringListValue() @fn QStringList Dtk::Core::DDesktopEntry::stringListValue(const QString &key, const QString §ion = "Desktop Entry") const @brief 返回给定 `section` 中与给定 `key` 关联的字符串的列表。如果destkop不包含为该键的项,则函数返回一个空字符串列表。 @return 返回给定 `section` 中与给定 `key` 关联的字符串的列表。 @sa rawValue() stringValue() localizedValue() @fn bool Dtk::Core::DDesktopEntry::setRawValue(const QString &value, const QString &key, const QString& section = "Desktop Entry") @brief 设置给定 `section` 中与给定 `key` 关联的原始字符串值。 @fn bool Dtk::Core::DDesktopEntry::setStringValue(const QString &value, const QString &key, const QString& section = "Desktop Entry") @brief 设置给定 `section` 中与给定 `key` 关联的字符串 @fn bool Dtk::Core::DDesktopEntry::setLocalizedValue(const QString &value, const QString& localeKey, const QString &key, const QString& section = "Desktop Entry") @brief 设置给定的 `key` 和 `section` 中的区域设置相关联的本地化字符串值。 @fn bool Dtk::Core::DDesktopEntry::removeEntry(const QString &key, const QString §ion = "Desktop Entry"); @brief 删除desktop中 `section` 与 `key` 对应的值 @fn static QString& Dtk::Core::DDesktopEntry::escape(QString &str) @brief 支持转义序列`\s`、`\n`、`\t`、`\r`和`\\`表示值 @details string和localestring类型的值支持转义序列`\s`、`\n`、`\t`、`\r`和`\\`,分别表示ASCII空格、换行符、制表符、回车和反斜杠。 @fn static QString& Dtk::Core::DDesktopEntry::escapeExec(QString &str) @brief 必须将参数括在双引号之间,并对双引号字符进行转义。 @details | 原字符 | 转义后 | |------|---------| | \` | "`" | | $ | "$" | | \ | "\" | 在它前面加上一个额外的反斜杠字符。实现必须在扩展字段代码之前和之前撤销引用,将参数传递给可执行程序。 @note 类型为string的值的通用转义规则规定,反斜杠字符也可以转义为("\\")和这个转义规则应用在引用规则之前。
因此,要明确地表示在desktop文件中,引号参数中的文字反斜杠字符
要求使用四个连续的反斜杠字符("\\\\")。同样,在桌面入口文件中引用参数中的美元符号表示为("\\$")。 @fn static QString& Dtk::Core::DDesktopEntry::unescape(QString &str, bool unescapeSemicolons = false) @brief 对于类型为string和localestring的值,支持转义序列`\s`、`\n`、`\t`、`\r`和`\\`,分别表示ASCII空格、换行符、制表符、回车符和反斜杠。 @details 有些键可以有多个值。这种情况下,`key` 的值被指定为复数形式: 例如,字符串。多个值应该用分号分隔,`key` 的值可以选择以分号结尾。空字符串必须以分号结尾。 这些值中的分号需要使用`\;`转义。 有关该规范本身的更多详细信息,请参阅: https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#value-types @fn static QString& Dtk::Core::DDesktopEntry::unescapeExec(QString &str) @brief 必须将参数括在双引号之间,并对双引号字符进行转义, @details | 原字符 | 转义后 | |------|---------| | \` | "`" | | $ | "$" | | \ | "\" | 在它前面加上一个额外的反斜杠字符。实现必须在扩展字段代码之前和之前撤销引用,将参数传递给可执行程序。 保留字符: | 功能 | 字符 | |---------------------|---------| | space | " " | | tab | | | newline | | | double quote | | | single quote | "'" | | backslash character | "\" | | greater-than sign | ">" | | less-than sign | "<" | | tilde | "~" | | vertical bar | \| | | ampersand | "&" | | semicolon | ";" | | dollar sign | "$" | | asterisk | "*" | | question mark | "?" | | hash mark | "#" | | parenthesis | "(" 和 ")" | | backtick character | "`" | @note 类型为string的值的通用转义规则规定
反斜杠字符也可以转义为("\\"),而且转义规则在引号规则之前应用。
因此,要在desktop文件的引号参数中明确表示字面上的反斜杠字符,需要使用四个连续的反斜杠字符(“\\\\”)。
同样,在desktop文件中,引号参数中的美元符号可以明确地表示为("\\$")。 @fn bool Dtk::Core::DDesktopEntry::setStatus(const Status &status) @brief 设置desktop文件解析状态 */ dtkcore-5.7.12/docs/global/dlicenseinfo.zh_CN.dox000066400000000000000000000032671476226660600216360ustar00rootroot00000000000000/*! @~chinese @ingroup dglobal @file include/global/dlicenseinfo.h @class Dtk::Core::DLicenseInfo::DComponentInfo @brief dcomponentinfo 是一组用于查询组件所用开源协议信息的类 @fn Dtk::Core::DLicenseInfo::DComponentInfo::DComponentInfo(DObject *parent) @brief 组件信息类的构造函数 @param[in] parent 组件信息类的父对象 @fn QString Dtk::Core::DLicenseInfo::DComponentInfo::name() @brief 获取组件的名称 @fn QString Dtk::Core::DLicenseInfo::DComponentInfo::version() @brief 获取组件的版本号 @fn QString Dtk::Core::DLicenseInfo::DComponentInfo::copyRight() @brief 获取组件的授权信息 @fn QString Dtk::Core::DLicenseInfo::DComponentInfo::licenseName() @brief 获取组件的所用开源许可协议名称 @class Dtk::Core::DLicenseInfo @brief dlicenseinfo是一组用于查询应用所用开源许可协议相关信息的类 @fn Dtk::Core::DLicenseInfo::DLicenseInfo(DObject *parent) @brief 开源许可协议信息类的构造函数 @param[in] parent 开源许可协议信息类的父对象 @fn bool Dtk::Core::DLicenseInfo::loadContent(const QByteArray &content) @brief 通过内容content加载协议 @return 0 加载失败 @return 1 加载成功 @fn bool Dtk::Core::DLicenseInfo::loadFile(const QString &file) @brief 通过文件file加载协议 @return 0 加载失败 @return 1 加载成功 @fn void Dtk::Core::DLicenseInfo::setLicenseSearchPath(const QString &path) @brief 设置协议内容路径path @fn QByteArray Dtk::Core::DLicenseInfo::licenseContent(const QString &licenseName) @brief 获取协议名为licenseName的内容 @fn DLicenseInfo::DComponentInfos Dtk::Core::DLicenseInfo::componentInfos() @brief 获取组件的相关信息 */ dtkcore-5.7.12/docs/global/dsysinfo.zh_CN.dox000066400000000000000000000273611476226660600210330ustar00rootroot00000000000000/*! @~chinese @ingroup dglobal @file include/global/dsysinfo.h @class Dtk::Core::DSysInfo @brief dsysinfo 是一组用于查询系统信息的静态类 @details ## 概述 dsysinfo是一组用于查询系统信息的静态类 项目目录结构如下: ```bash ├── CMakeLists.txt └── main.cpp ``` ## CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.13) # cmake版本要求 set (VERSION "1.0.0" CACHE STRING "define project version") # 定义项目版本 set(BIN_NAME test) # 定义项目名称 project(test) # 定义项目名称 file(GLOB_RECURSE SRCS "*.h" "*.cpp") # 定义项目源文件 find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5 find_package(DtkCore REQUIRED) # 寻找DtkCore add_executable(test main.cpp # 源文件 ) target_link_libraries(test PRIVATE ${DtkCore_LIBRARIES} # 链接DtkCore Qt5::Core # 链接Qt5 ) ``` ## main.cpp ```cpp #include // 引入DSysInfo #include // 引入qdebug.h DCORE_USE_NAMESPACE // 使用dtkcore命名空间 int main(int argc, char **argv) { qDebug() << DSysInfo::deepinType(); // 打印deepin类型 qDebug() << DSysInfo::ProductType(); // 打印产品类型 return 0; } ``` @enum Dtk::Core::DSysInfo::ProductType @brief 产品信息 @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Deepin @brief 深度操作系统 @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::ArchLinux @brief ArchLinux @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::CentOS @brief CentOS @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Debian @brief Debian @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Fedora @brief Fedora @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::LinuxMint @brief LinuxMint @var Dtj::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Manjaro @brief Manjaro @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::openSUSE @brief openSUSE @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::SailfishOS @brief SailfishOS @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Ubuntu @brief Ubuntu @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Uos @brief UOS @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Gentoo @brief Gentoo @var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::NixOS @brief NixOS @enum Dtk::Core::DSysInfo::DeepinType @brief 深度操作系统版本 @var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::UnknownDeepin @brief 未知版本 @var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinDesktop @brief 桌面版 @var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinProfessional @brief deepin专业版, 现为uos专业版 @var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinServer @brief deepin服务器版本, 现为uos服务器版 @var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinPersonal @brief deepin个人版, 现为uos家庭版 @enum Dtk::Core::DSysInfo::LogoType @brief 系统的logo类型 @var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Normal @brief 正常 @var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Light @brief 亮色 @var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Symbolic @brief 符号 @var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Transparent @brief 水印 @enum Dtk::Core::DSysInfo::OrgType @brief 组织类型 @var Dtk::Core::DSysInfo::OrgType Dtk::Core::DSysInfo::Distribution @brief 当前版本 @var Dtk::Core::DSysInfo::OrgType Dtk::Core::DSysInfo::Distributor @brief 当前发行版 @var Dtk::Core::DSysInfo::OrgType Dtk::Core::DSysInfo::Manufacturer @brief 当前发行版或设备的制造商 @enum Dtk::Core::DSysInfo::UosType @brief UOS版本类型 @var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosTypeUnknown @brief 未知版本 @var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosDesktop @brief UOS桌面版 @var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosServer @brief UOS服务器版 @var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosDevice @brief UOS设备版 @var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosTypeCount @brief 记录枚举数量 @enum Dtk::Core::DSysInfo::UosEdition @brief 详细uos版本 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEditionUnknown @brief 未知版本 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosProfessional @brief UOS专业版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosHome @brief UOS家庭版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosCommunity @brief 社区版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosMilitary @brief * @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEnterprise @brief UOS企业版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEnterpriseC @brief UOS行业版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEuler @brief UOS服务器欧拉版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosMilitaryS @brief * @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosDeviceEdition @brief UOS专用设备版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEducation @brief UOS教育版 @var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEditionCount @brief 记录枚举数量 @enum Dtk::Core::DSysInfo::UosArch @brief UOS使用的架构 @var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosArchUnknown @brief 未知架构 @var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosAMD64 @brief x86_64 @var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosARM64 @brief arm64 @var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosMIPS64 @brief mips64 @var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosSW64 @brief sw_64 @fn static bool Dtk::Core::DSysInfo::isDeepin() //FIXME: 显示错乱 无法修复 @brief 是否为 deepin 或 uos 系统 @return 0 不是 deepin 或 uos 系统 @return 1 是 deepin 或 uos 系统 @fn static bool Dtk::Core::DSysInfo::isDDE() @brief 是否使用 dde 桌面环境 @note 此方法仅在 linux 平台下可用 @fn static DeepinType Dtk::Core::DSysInfo::deepinType() @brief deepin 系统类型 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::deepinTypeDisplayName (const QLocale &locale=QLocale::system()) @brief 显示的 deepin 发行版类型名称 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::deepinVersion() @brief deepin 版本 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::deepinCopyright() @brief deepin 开源许可协议 @note 此方法仅在 linux 平台下可用 @fn static UosEdition Dtk::Core::DSysInfo::uosEditionType() @brief DSysInfo::osEditionType 版本类型 显示版本类型 专业版/个人版/社区版.. @note 根据 osBuild.B && osBuild.D @note 此方法仅在 linux 平台下可用 @fn static UosArch Dtk::Core::DSysInfo::uosArch() @brief DSysInfo::osArch 架构信息 @details(使用一个字节的二进制位, 从低位到高位) 【0x8 sw64】【0x4 mips64】【0x2 arm64】【0x1 amd64】 @note 此处架构是从 OsBuild 获取的系统版本的 Arch 信息, 并不是指硬件的 Arch 信息 @note 此方法仅在 linux 平台下可用 @fn static QString uosProductTypeName(const QLocale &locale=QLocale::system()) @brief DSysInfo::osProductTypeName 版本名称 @details ProductType[xx] 项对应的值, 如果找不到对应语言的默认使用 ProductType 的值(Desktop/Server/Device) locale 当前系统语言 @fn static QString Dtk::Core::DSysInfo::uosSystemName(const QLocale &locale=QLocale::system()) @brief SystemName[xx] 项对应的值 @details 如果找不到对应语言的默认使用 SystemName 的值 Uniontech OS locale 当前系统语言 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::function uosEditionName(const QLocale &locale=QLocale::system()) @brief 版本名称 EditionName[xx] 项对应的值 @details 如果找不到对应语言的默认使用 EditionName 的值(Professional/Home/Community...) locale 当前系统语言 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::spVersion() @brief 阶段版本名称 @details 小版本号 A-BC-D 中 BC、 A.B.C 中的 B 返回 SP1-SPxx, 如果正式版返回空 X.Y.Z模式下暂不支持返回此版本号 @note minVersion.BC == 00 正式版本, minVersion.BC | minVersion.B == 01-99 SP1….SP99 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::udpateVersion() @brief 更新版本名称 小版本号 A-BC-D 中 D、A.B.C 模式中的 C 返回 update1… update9, 如果正式版返回空 X.Y.Z 模式下暂不支持返回此版本号 @note minVersion.D == 0;正式版本 minVersion.D | minVersion.C == 1-9;update1… update9, updateA...updateZ @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::majorVersion() @brief 主版本号 主版本号 【20】【23】【25】【26】【29】【30】 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::minorVersion() @brief 小版本号 【ABCD】 ·[0-9]{4} 【A.B.C】 或者【X.Y.Z】 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::buildVersion() @brief 小版本号 系统镜像批次号, 按时间顺序(不可回退)从100-999递增 @note 此方法仅在 linux 平台下可用 @fn static QString Dtk::Core::DSysInfo::distributionInfoPath () @brief 返回 distribution 文件地址 一般在`/usr/share/deepin/`目录下 @fn static QString Dtk::Core::DSysInfo::distributionInfoSectionName(OrgType type) @brief 返回 distribution.info 文件中 SectionName 字段的值 @fn static Dtk::Core::DSysInfo::distributionOrgName(OrgType type=Distribution, const QLocale &locale=QLocale::system()) @brief 返回组织名称 @details 使用类型为Distribution来获取当前deepin distribution本身的名称 @fn static QPairDtk::Core::DSysInfo::distributionOrgWebsite(OrgType type=Distribution) @brief 发行版组织的网站名称和网址。使用 type 作为 Distribution 获取当前 deepin 发行版本身的名称。 @fn static QString Dtk::Core::DSysInfo::distributionOrgLogo(OrgType orgType=Distribution, LogoType type=Normal, const QString &fallback=QString()) @brief 获得的组织logo路径, 如果不存在, 则返回给定的其他路径 @details 使用 type 作为 Distribution 获取当前 deepin 发行版本身的logo。 @fn static QString Dtk::Core::DSysInfo::operatingSystemName() @brief 操作系统名 @fn static ProductType Dtk::Core::DSysInfo::productType() @brief 产品类型 @fn static QString Dtk::Core::DSysInfo::productVersion() @brief 产品版本 @fn static bool Dtk::Core::DSysInfo::isCommunityEdition() @brief 检查当前版本是否是社区版 开发者可以使用这种方式来检查我们是否需要启用或禁用社区版或企业版的功能。 @details 目前的规则: 专业版、服务器版、个人版(DeepinType)将被视为企业版。
Uos(ProductType)将被视为企业版。 @fn static QString Dtk::Core::DSysInfo::computerName() @brief 电脑名 @fn static QString Dtk::Core::DSysInfo::cpuModelName() @brief cpu模式名 @fn static qint64 Dtk::Core::DSysInfo::memoryInstalledSize() @brief 内存安装大小 @fn static qint64 Dtk::Core::DSysInfo::memoryTotalSize() @brief 实际内存大小 @fn static qint64 Dtk::Core::DSysInfo::systemDiskSize() @brief 系统磁盘大小 @fn static QDateTime Dtk::Core::DSysInfo::bootTime () @brief 系统启动时间点 @fn static QDateTime Dtk::Core::DSysInfo::shutdownTime () @brief 上一次正常关机时间点(重启也会被记录在内) @fn static qint64 Dtk::Core::DSysInfo::uptime() @brief 系统启动到现在时长 @note 参见`cat /proc/uptime`命令 @fn static Arch Dtk::Core::DSysInfo::arch @brief cpu架构信息 @note 此处架构是从gcc编译器获取的 */ dtkcore-5.7.12/docs/global/index.zh_CN.md000066400000000000000000000025611476226660600201050ustar00rootroot00000000000000@page global global--dtk全局工具组件 # DTk global:dtk全局工具类 ## dsysinfo:dtk系统信息工具类 [dsysinfo.h 详细文档](dsysinfo_8h.html)
这里放一个最小化使用dsysinfo的例子:
cmake: ```cmake cmake_minimum_required(VERSION 3.13) # cmake版本要求 set (VERSION "1.0.0" CACHE STRING "define project version") # 定义项目版本 set(BIN_NAME test) # 定义项目名称 project(test) # 定义项目名称 file(GLOB_RECURSE SRCS "*.h" "*.cpp") # 定义项目源文件 find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5 find_package(DtkCore REQUIRED) # 寻找DtkCore add_executable(test main.cpp # 源文件 ) target_link_libraries(test PRIVATE ${DtkCore_LIBRARIES} # 链接DtkCore Qt5::Core # 链接Qt5 ) ``` cpp: ```cpp #include // 引入DSysInfo #include // 引入qdebug.h DCORE_USE_NAMESPACE // 使用dtkcore命名空间 int main(int argc, char **argv) { qDebug() << DSysInfo::deepinType(); // 打印deepin类型 qDebug() << DSysInfo::ProductType(); // 打印产品类型 return 0; } ``` 其余的组件使用方法类似,这里就不一一列举了 @defgroup dglobal @brief dtk设置全局工具组件 @details dtk全局工具组件,提供了设置全局工具的功能。
包含以下功能: * dsysinfo:dtk系统信息工具类 * dconfig:dtk配置文件工具类 dtkcore-5.7.12/docs/log/000077500000000000000000000000001476226660600147715ustar00rootroot00000000000000dtkcore-5.7.12/docs/log/AbstractAppender.zh_CN.dox000066400000000000000000000101211476226660600217220ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/AbstractAppender.h AbstractAppender类是所有可以与Logger一起使用的日志appender的基础接口类。 @class Dtk::Core::AbstractAppender @brief AbstractAppender为应用消息的线程安全、互斥保护的日志提供了一个通用的实现 @details AbstractAppender为应用消息的线程安全、互斥保护的日志提供了一个通用的实现,例如ConsoleAppender、FileAppender或其他的东西。
AbstractAppender是抽象的,不能被实例化,但是你可以使用它的任何一个子类,或者根据你的选择创建一个自定义的日志appender。
Appenders是逻辑设备,旨在通过调用`Logger::registerAppender()`附加到Logger对象。在每个来自应用程序的日志记录调用中,Logger对象都会依次调用所有在它身上注册的appender的`write()`函数。
你可以子类化AbstractAppender来实现你喜欢的任何类型的日志目标。它可以是外部日志子系统(例如,*nix中的syslog)、XML文件、SQL数据库条目、D-Bus消息或任何你能想到的其他东西。
对于简单的非结构化的纯文本日志(例如,到一个纯文本文件或到控制台输出),请子类化AbstractStringAppender而不是AbstractAppender,这将给你一个更方便的方法来控制日志输出的格式。 @fn AbstractAppender Dtk::Core::AbstractAppender::AbstractAppender() @brief AbstractAppender构造函数 @fn AbstractAppender Dtk::Core::AbstractAppender::~AbstractAppender() @brief AbstractAppender析构函数 @fn Logger::LogLevel Dtk::Core::AbstractAppender::detailsLevel() @brief 返回appender的当前日志级别 @details 返回appender的当前日志级别.日志级别低于当前`detailsLevel()`的日志记录将被appender默认忽略, 并且不会被发送到其append()函数。 它提供了额外的日志灵活性,允许你为不同类型的日志设置不同的记录等级 @note 该函数是线程安全的 @sa setDetailsLevel() @sa Logger::LogLevel @return 日志记录等级 @fn void Dtk::Core::AbstractAppender::setDetailsLevel(Logger::LogLevel level) @brief 设置当前appender的记录级别,默认记录级别为Logger::Debug @note 该函数是线程安全的 @sa setDetailsLevel() @sa Logger::LogLevel @fn void Dtk::Core::AbstractAppender::setDetailsLevel(const QString &level) @brief 设置当前appender的记录级别,这个函数是为了简化输入而提供的,它的行为与同名函数类似。 @sa AbstractAppender::setDetailsLevel(Logger::LogLevel level) @sa setDetailsLevel() @sa Logger::LogLevel @fn void Dtk::Core::AbstractAppender::write(const QDateTime &time, Logger::LogLevel level, const char *file, int line, const char *func, const QString &category, const QString &msg) @brief 尝试写入日志,这是由Logger对象调用的函数,用于向appender写入日志信息 @param[in] time 时间戳 @param[in] level 日志记录等级 @param[in] file 目标文件名 @param[in] line 要输出的行数 @param[in] func 输出的函数名称 @param[in] category 日志类别 @param[in] msg 输出信息 @note 该函数是线程安全的 @sa Logger::write() @sa detailsLevel() @fn void Dtk::Core::AbstractAppender::AbstractAppender::append(const QDateTime &timeStamp, Logger::LogLevel level, const char *file, int line, const char *function, const QString &category, const QString &message) = 0 @brief 将日志记录写到logger实例中 @details 每次当用户试图使用`write()`函数向这个AbstractAppender实例写入消息时,都会调用这个函数。`write()`函数作为代理工作,只输出日志级别大于或等于当前`logLevel()`的消息 @note 当你实现一个自定义的appender时,需要重载这个函数。 @note 该函数不需要是线程安全的,因为它不会被Logger对象直接调用。`write()`函数作为代理,保护该函数不被并发调用。 @param[in] timeStamp 时间戳 @param[in] level 日志记录等级 @param[in] file 目标文件名 @param[in] line 要输出的行数 @param[in] function 输出的函数名称 @param[in] category 日志类别 @param[in] message 输出信息 */ dtkcore-5.7.12/docs/log/AbstractStringAppender.zh_CN.dox000066400000000000000000000130661476226660600231240ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/AbstractStringAppender.h @class Dtk::Core::AbstractStringAppender @brief AbstractStringAppender类为处理纯文本格式的Appender提供了一个方便的基础日志 @details AbstractStringAppender是AbstractAppender类的简单扩展, 它提供了一种方便的方式来创建自定义日志应用程序, 该程序使用纯文本格式的日志. 它有`formattedString()`保护类型(不可直接被调用)函数, 可以根据`setFormat()`设置的格式来格式化日志参数。 @note 这个类不能直接实例化, 因为它包含从AbstractAppender类继承的纯虚函数。 @brief 关于自定义日志输出格式的更详细描述, 请参见setFormat()函数的文档 @sa AbstractStringAppender::setFormat() @fn AbstractStringAppender Dtk::Core::AbstractStringAppender::AbstractStringAppender() @brief 构建一个新的字符串appender对象 @fn QString Dtk::Core::AbstractStringAppender::format() @brief 返回当前使用的format字符串 @details 默认记录格式为:`"%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n"` 你可以使用setFormat()函数来设置不同的日志记录格式。 @sa AbstractStringAppender::setFormat() @return 返回当前使用的format字符串 @fn void Dtk::Core::AbstractStringAppender::setFormat(const QString &format) @brief 设置日志格式, 以便用这个appender向日志目标写入字符串。 @details 对于那些使用过标准sprintf函数的开发者来说, 字符串格式非常常见。 日志输出格式是一个简单的QString, 带有特殊的标记(以%符号开始), 在写日志记录时将被替换成它的内部含义。 控制标记以百分号(%)开始, 后面是{}括号内的命令(该命令描述了将被放入日志记录而不是标记的内容)。 可选的字段宽度参数可以在命令后直接指定(通过括号内的冒号), 有些命令需要一个额外的格式化参数(在第二个{}括号内) 字段宽度参数的工作原理与`QString::arg()`fieldWidth参数几乎相同(并在内部使用它), 例如, "%{type:-7}"将被替换为消息的左边填充的调试级别("Debug")或其他东西。更详细的描述请参考Qt文档。 @details 支持的标记: | **标记** | **含义** | **备注** | |:-----------:|:-----------------------------------------------------:|:-------------------------------------------------------------------:| | %{time} | 时间戳。你可以使用标记后的第二个{}括号来指定你的自定义时间戳格式。默认格式:"HH:mm:ss.zzz" | "%{time}{dd-MM-yyyy, HH:mm}"可能被替换为 "20-9-2022, 21:24", 这取决于当前的日期和时间。 | | %{type} | 日志级别。可能的日志级别在Logger::LogLevel枚举中显示。 | | | %{Type} | 大写的日志级别 | | | %{typeOne} | 一个字母的日志级别 | | | %{TypeOne} | 一个大写字母的日志级别 | | | %{File} | 记录日志的文件的完整源文件名(含路径), 使用 `__FILE__`预处理程序宏 | | | %{file} | 简短的文件名(去除路径后的文件名) | | | %{line} | 源文件中的行数。使用`__LINE__`预处理程序宏。 | | | %{Function} | 调用`LOG_*`宏的函数的名称。使用Qt提供的`Q_FUNC_INFO`宏。 | | | %{function} | 类似于%{Function}, 但使用 stripFunctionName 剥离了函数名。 | | | %{message} | 日志内容 | | | %{category} | 日志类别 | | | %{appname} | 应用程序名称(由`QCoreApplication::applicationName()`函数返回) | | | %{pid} | 应用程序的pid(由`QCoreApplication::applicationPid()`函数返回) | | | %{threadid} | 线程ID | | | %% | 转译为单`%`标记 | | @fn static QString Dtk::Core::AbstractStringAppender::stripFunctionName(const char *name) @brief 剥离长函数签名(由Q_FUNC_INFO宏添加) @details 字符串处理掉了函数的返回类型、参数和模板参数, 这对于提高日志输出的可读性是非常有用的 @param[in] name 函数名称 @return 剥离的函数名称 */ dtkcore-5.7.12/docs/log/ConsoleAppender.zh_CN.dox000066400000000000000000000023571476226660600215750ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/ConsoleAppender.h @class Dtk::Core::ConsoleAppender @brief ConsoleAppender是简单的控制台appender,将日志记录写入`std::cerr`输出流
@details ConsoleAppender使用`[%{type:-7}] <%{function}> %{message}\n`作为默认输出格式。它类似于AbstractStringAppender,但不显示时间
你可以通过使用`QT_MESSAGE_PATTERN`环境变量来修改ConsoleAppender的输出格式,而不用修改你的代码。 变量。如果你需要你的应用程序忽略这个环境变量,你可以调用`ConsoleAppender::ignoreEnvironmentPattern(true)` @fn ConsoleAppender Dtk::Core::ConsoleAppender::ConsoleAppender() @brief 构造函数,设置默认的日志格式为`[%{type:-7}] <%{function}> %{message}\n` @fn virtual QString Dtk::Core::ConsoleAppender::format() @brief 返回当前默认输出格式,可以调用父类的`setFormat()`来更改日志输出格式 @sa AbstractStringAppender::setFormat() @fn void Dtk::Core::ConsoleAppender::ignoreEnvironmentPattern(bool ignore) @brief 设置应用程序忽略环境变量来修改ConsoleAppender的输出格式,使用默认输出格式 @sa [QT_MESSAGE_PATTERN](https://doc.qt.io/qt-5/debug.html#warning-and-debugging-messages) */ dtkcore-5.7.12/docs/log/FileAppender.zh_CN.dox000066400000000000000000000016331476226660600210460ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/FileAppender.h @class Dtk::Core::FileAppender @brief 简单的文件appender,将日志记录写到纯文本文件中 @fn FileAppender Dtk::Core::FileAppender::FileAppender(const QString &fileName = QString()) @brief 构造函数,指定日志记录文件的文件名。 @fn QString Dtk::Core::FileAppender::fileName() const @brief 返回由setFileName()设置的名称,或返回FileAppender构造函数传入的fileName @sa FileAppender::setFileName() @fn void Dtk::Core::FileAppender::setFileName(const QString &s) @brief 设置文件的名称。该名称可以没有路径,可以是相对路径,也可以是绝对路径 @sa FileAppender::fileName() @fn qint64 Dtk::Core::FileAppender::size() @brief 返回日志文件大小 @fn bool FileAppender::openFile() @brief 打开日志记录文件 @fn void FileAppender::closeFile() @brief 关闭日志记录文件 */ dtkcore-5.7.12/docs/log/Logger.zh_CN.dox000066400000000000000000000226731476226660600177360ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/Logger.h @class Dtk::Core::Logger Logger.h @brief 非常简单但相当强大的组件,可用于记录你的应用程序活动。 @enum Dtk::Core::Logger::LogLevel @brief 日志等级 @var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Trace 追踪级别,可用于大部分不需要的记录,用于内部代码追踪 @var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Debug 调试级别,用于软件的调试。 @var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Info 信息级别,可用于信息记录,这可能不仅对开发者有意义 @var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Warning 警告,可以用来记录你的应用程序检测到的一些非致命的警告 @var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Error 错误,可能是一个较大问题,导致你的程序工作出错,但不至于崩溃 @var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Fatal 致命错误,用于不可恢复的错误,在写入日志记录后立即崩溃应用程序(终止) @fn Logger Dtk::Core::Logger::Logger() @brief 构建Logger的实例。 @note 如果你只使用一个全局的logger实例,不需要手动使用这个构造函数,可以考虑使用logger宏来代替访问记录器实例 @fn Logger Dtk::Core::Logger::Logger(const QString &defaultCategory) @brief 构建Logger的实例并设置Logger的默认类别 @note 如果你只使用一个全局的logger实例,不需要手动使用这个构造函数, 可以考虑使用logger宏来访问logger实例并调用setDefaultCategory方法 @sa Logger::Logger() @sa Logger::setDefaultCategory() @fn Logger Dtk::Core::Logger::~Logger() @brief 析构函数 @note 你可能不需要直接使用这个函数。记录器的全局实例将在你的QCoreApplication执行结束后自动销毁 @fn static Logger* Dtk::Core::Logger::globalInstance() @brief 返回Logger的全局对象 @note 在大多数情况下,你不应该直接使用这个函数。可以考虑使用 [logger](@ref logger) 宏来代替 @return Logger指针 @fn static QString Dtk::Core::Logger::levelToString(Logger::LogLevel level) @brief 将LogLevel枚举值转换为其字符串表示 @sa Logger::LogLevel @fn static LogLevel Dtk::Core::Logger::levelFromString(const QString &str) @brief 将LogLevel字符串表示转换为枚举值 @note 字符串的比较是不分大小写的。如果提供的日志级别字符串不合法,则返回`Logger::Debug`的枚举值 @sa Logger::LogLevel @sa Logger::levelToString() @fn void Dtk::Core::Logger::registerAppender(AbstractAppender *appender) @brief 注册appender来写入日志记录
在写入日志的调用中(使用其中一个宏或`write()`函数),Logger遍历appender列表,并向每个appender写入日志记录。请查阅AbstractAppender文档以了解appenders的概念。 如果没有appender被添加到Logger中,它就会退回到记录到`std::cerr`流中。 @param[in] appender 要在Logger中注册的Appender @note Logger对appender拥有所有权,它将在应用程序退出时删除它。因此,appender必须在堆上创建,以防止appender被重复销毁。 @sa Logger::registerCategoryAppender() @sa Dtk::Core::AbstractAppender @fn void Dtk::Core::Logger::registerCategoryAppender(const QString &category, AbstractAppender *appender) @brief 注册appender,将日志记录写到特定的类别中
@details 调用这个方法,你可以将一些appender与命名的类别联系起来。 在调用特定类别的日志写入时(直接调用带有类别参数的`write()`,写入默认类别,或使用特殊的`dCDebug()`、`dCWarning()`等宏), Logger只将日志信息写入注册的类别appender列表中。
你可以调用`logToGlobalInstance()`将所有类别的日志信息传递给全局的Logger实例Appender(使用`registerAppender()`注册)。 如果没有特定名称的类别应用程序被注册到记录器上,它就会退回到记录到`std::cerr` STL流中,这两种方法都有简单的警告信息。 @param[in] category 类别名称 @param[in] appender 要在Logger中注册的Appender @note Logger对appender拥有所有权,它将在应用程序退出时删除它。根据这一点,appender必须在堆上创建,以防止appender被重复销毁。 @sa Logger::registerAppender() @sa Logger::logToGlobalInstance() @sa Logger::setDefaultCategory() @fn void Dtk::Core::Logger::logToGlobalInstance(const QString &category, bool logToGlobal = false) @brief 将一些日志类别与全局日志实例应用者联系起来。 如果logToGlobal设置为 "true",所有到指定类别的Logger的日志消息也将被写入全局日志实例appenders(使用`registerAppender()`注册)
默认情况下,所有到特定类别的消息都只写到特定的类别应用者 (使用 `registerCategoryAppender()` 注册) @param[in] category 类别名称 @param[in] logToGlobal 是否将日志写入全局日志appenders @sa Logger::registerAppender() @sa Logger::globalInstance() @sa Logger::registerCategoryAppender() @fn void Dtk::Core::Logger::setDefaultCategory(const QString &category); QString defaultCategory() @brief 设置默认的日志类别 所有到这个类别应用的日志信息也将被写入一般的日志实例应用(使用[registerAppender](@ref registerAppender)方法注册),反之亦然 特别是,任何对dDebug()宏的调用都将被视为类别日志 所以你不需要用dCDebug()宏来指定类别名称 要取消默认的类别,传递一个空字符串作为参数 @param[in] category 类别名称 @note "category "格式标记将被设置为所有这些消息的类别名称 @sa Dtk::Core::AbstractStringAppender::setFormat() @sa Logger::defaultCategory() @sa Logger::registerCategoryAppender() @sa Logger::logToGlobalInstance() @fn QString Dtk::Core::Logger::defaultCategory() @brief 返回默认的日志类别名称 @sa Logger::setDefaultCategory() @fn void Dtk::Core::Logger::write(const QDateTime &time, LogLevel level, const char *file, int line,const char *func, const char *category, const QString &msg) @brief 写入日志记录。 将带有所提供参数的日志记录写给所有注册的应用 @param[in] time 时间戳 @param[in] level 日志记录等级 @param[in] file 目标文件名 @param[in] line 要输出的行数 @param[in] func 输出的函数名称 @param[in] category 日志类别 @param[in] msg 输出信息 @note 使用`Logger::Fatal`日志级别记录日志记录将导致调用STL `abort()`函数, 这将中断你的软件的运行并Core dump @sa Logger::LogLevel @sa Dtk::Core::AbstractAppender @fn void Dtk::Core::Logger::write(LogLevel level, const char *file, int line, const char *func, const char *category, const QString &msg) @brief 这是为方便而提供的重载函数。它的行为与同名函数类似,此函数无需传入time参数 @note 这个函数使用了`QDateTime::currentDateTime()`用获得的当前时间戳 @sa Logger::write(const QDateTime &time, LogLevel level, const char *file, int line,const char *func, const char *category, const QString &msg) @param[in] level 日志记录等级 @param[in] file 目标文件名 @param[in] line 要输出的行数 @param[in] func 输出的函数名称 @param[in] category 日志类别 @param[in] msg 输出信息 @fn QDebug Dtk::Core::Logger::write(LogLevel level, const char *file, int line,const char *func, const char *category) @brief 这是为方便而提供的重载函数。它的行为与同名函数类似,此函数无需传入message参数 @details 这个函数不接受任何日志信息作为参数。它返回的是可以使用流函数写入的`QDebug`对象
例如,你可能想写: @code dDebug() << "This is the size" << size << "of the element" << elementName; @endcode 而不是写为: @code dDebug(QString(QLatin1String("This is the size %1x%2 of the element %3")).arg(size.x()).arg(size.y()).arg(elementName)); @endcode 这样会更优雅一些
请考虑阅读Qt参考文档,了解QDebug类的使用语法 @note 这个重载肯定是最好用的一个重载,但是代价是它会比其他的重载更为慢 @sa Logger::write(const QDateTime &time, LogLevel level, const char *file, int line,const char *func, const char *category, const QString &msg) @param[in] level 日志记录等级 @param[in] file 目标文件名 @param[in] line 要输出的行数 @param[in] func 输出的函数名称 @param[in] category 日志类别 @fn void Dtk::Core::Logger:: writeAssert(const char *file, int line, const char *func, const char *condition) @brief 写入断言 @details 这个函数使用write()函数来写断言记录
断言记录总是使用`Logger::Fatal`日志级别来写,这将导致程序的中止和核心转储(core dump)的生成(如果支持) 写入appenders的信息与传入参数相同,前缀为 `ASSERT:` @param[in] file 目标文件名 @param[in] line 要输出的行数 @param[in] func 输出的函数名称 @note 不建议直接调用这个函数,你可以直接调用`LOG_ASSERT`宏,它将为这个函数提供所有需要的信息 @sa Logger::write(const QDateTime &time, LogLevel level, const char *file, int line,const char *func, const char *category, const QString &msg) */ dtkcore-5.7.12/docs/log/RollingFileAppender.zh_CN.dox000066400000000000000000000063061476226660600223770ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/RollingFileAppender.h @class Dtk::Core::RollingFileAppender @brief RollingFileAppender类扩展了FileAppender,使日志文件在按照用户指定的频率进行滚动 @details 该类是基于`Log4Qt.DailyRollingFileAppender`类[Log4Qt](http://log4qt.sourceforge.net/) 并具有相同的日期模式格式
例如,如果fileName设置为`/foo/bar`,DatePattern设置为每日滚动('.yyy-MM-dd'.log'),在2022-05-28的午夜。 日志文件`/foo/bar.log`将被复制到`/foo/bar.2022-05-28.log`,2022-05-29的日志将在`/foo/bar`中继续,直到第二天滚动
logFilesLimit参数用于在滚动期间自动删除目录中最旧的日志文件。 (所以在任何时候,目录中都不会有超过logFilesLimit的最新日志文件存在) @enum Dtk::Core::RollingFileAppender::DatePattern @brief 日志频率 @var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::MinutelyRollover @brief 每分钟的日期模式字符串是`.yyyy-MM-dd-hh-mm` @var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::HourlyRollover @brief 每小时的日期模式字符串是 `.yyyy-MM-dd-hh` @var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::HalfDailyRollover @brief 每半天的日期模式字符串是`.yyyy-MM-dd-a` @var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::DailyRollover @brief 每天的日期模式字符串是`.yyyy-MM-dd` @var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::WeeklyRollover @brief 每周的日期模式字符串是`.'yyyy-ww` @var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::MonthlyRollover @brief 每月的日期模式字符串是`.yyyy-MM` @fn RollingFileAppender Dtk::Core::RollingFileAppender::RollingFileAppender() @brief 构造函数,默认限制日志文件个数是0,默认日志文件大小是1024*1024*20=20m @fn DatePattern Dtk::Core::RollingFileAppender::datePattern() @brief 返回当前的滚动更新频率 @sa RollingFileAppender::DatePattern @fn void Dtk::Core::RollingFileAppender::setDatePattern(DatePattern datePattern) @brief 设置日志滚动频率 @sa RollingFileAppender::DatePattern @fn void Dtk::Core::RollingFileAppender::setDatePattern(const QString &datePattern) @brief 此重载是为了方便使用,可以传入一个滚动频率字符串 @sa RollingFileAppender::DatePattern @sa RollingFileAppender::setDatePattern(DatePattern datePattern) @fn QString Dtk::Core::RollingFileAppender::datePatternString() @brief 以字符串形式,返回当前滚动频率 @fn void Dtk::Core::RollingFileAppender::setLogFilesLimit(int limit) @brief 设置日志文件数量上限,最旧的文件会被滚动覆盖 @fn int Dtk::Core::RollingFileAppender::logFilesLimit() @brief 返回设置的日志文件数量上限 @sa RollingFileAppender::setLogFilesLimit() @fn int Dtk::Core::RollingFileAppender::setLogSizeLimit(int qint64) @brief 设置日志文件单个文件大小上限 @fn qint64 Dtk::Core::RollingFileAppender::logSizeLimit() @brief 返回设置的日志文件单个文件大小上限 @sa RollingFileAppender::setLogSizeLimit(int qint64) */ dtkcore-5.7.12/docs/log/dlogmanager.zh_CN.dox000066400000000000000000000046371476226660600207770ustar00rootroot00000000000000/*! @~chinese @ingroup dlog @file include/log/LogManager.h @class Dtk::Core::DLogManager @brief DLogManager是dtk日志管理类,提供对日志的基础设置 @details 使用此类可以很方便的为自己的dtk程序加上日志,一般情况下应用如果需要写入日志只需要调用此类 调用相应的注册方法设置存储路径相关信息即可 @fn static void Dtk::Core::DLogManager::registerConsoleAppender() @brief 注册默认的控制台记录器 @fn static void Dtk::Core::DLogManager::registerFileAppender() @brief 注册默认的文件记录器,默认的文件记录器类型为RollingFileAppender. @note 输出日志默认文件位置为`~/.cache//.log`如果获取 $HOME 环境变量失败将不写日志. 如果在创建程序的时候没有指定这两个name,如果未设置organizationName,则是 `~/.cache//.log` 如果applicationName没有设置, 会fallback到进程二进制文件名 @sa DLogManager::setlogFilePath() @fn static void Dtk::Core::DLogManager::registerJournaldAppender() @brief 注册默认的journald记录器 @note 此方法只在linux下有效 @detials 默认输出文件位置为`/var/log/journal/.journal`,前提是此目录存在且有写权限, 如果目录不存在,systemd将不会自动创建此目录,并将日志写入到`/run/log/journal/.journal`中,此目录不支持持久化存储, 将在下次重启后丢失。 @note 查看日志可用`journalctl`命令,查看详细信息可用`journalctl -o verbose`命令,也可以使用deepin 日志查看器查看 @fn static QString Dtk::Core::DLogManager::getlogFilePath() @brief 获取当前的日志存储路径,包括文件名 @fn static void Dtk::Core::DLogManager::setlogFilePath(const QString &logFilePath) @brief 设置log文件路径。如果文件存在且不是log文件类型(比如文件夹)会导致设置无效并输出一条警告。 @note 注意,此文件路径为包括具体文件名的绝对路径。需要此文件不存在或者存在且为有效类型(xxx.log),一般情况下无需手动指定路径。 @fn static void Dtk::Core::DLogManager::setLogFormat(const QString &format) @brief 设置日志的格式,如果没有设置格式 @details 默认的格式为:`"%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"` @sa Dtk::Core::AbstractStringAppender::format() */ dtkcore-5.7.12/docs/log/index.zh_CN.md000066400000000000000000000110421476226660600174200ustar00rootroot00000000000000@page DLog dlog--DTK日志组件 # Dlog:DTK日志组件 ## 简介 DTK日志组件,提供了日志的输出、日志级别的设置、日志文件的设置等功能。为了简化日志的使用,我们提供了两种使用方式,一种是使用宏,另一种是使用类。 但是更为建议使用宏的方式进行使用。因为使用宏可以输出更多的信息,比如文件名、函数名、行号等。 ## 使用 ### 宏 DTK日志组件提供了一系列的宏,用于输出日志。这些宏的定义在dloggerdefs.h中 如果需要使用宏,则需要在你的代码中包含`DLog`文件。 @note DTK更推荐使用CPP标准引入头文件的方式,即使用`#include `的方式引入头文件,而不是使用`#include "xxxxx.h"`的方式引入头文件。 示例代码如下: ```cpp #include #include DCORE_USE_NAMESPACE int main(int argc, char **argv) { QCoreApplication app(argc, argv); #ifdef Q_OS_LINUX DLogManager::registerJournalAppender(); #endif DLogManager::registerConsoleAppender(); dDebug() << "this is a debug message"; return app.exec(); } ``` 上述代码中,我们使用了dDebug()宏,用于输出一条debug级别的日志。在输出日志时,我们可以使用`<<`运算符,将多个变量输出到日志中。 注意,registerJournalAppender()仅在Linux平台下有效,因为journal仅在Linux平台下有效。而registerConsoleAppender()则是在所有平台下都有效。 ### 类 使用类的方式需要先创建一个logger对象,然后使用logger对象的方法来输出日志,具体请参见logger文档 ## 注意事项 ### 日志级别 DTK使用的日志级别与Qt的日志级别一致,分别为:Trace、Debug、Info、Warning、Error、Fatal。其中Trace是最低级别,Fatal是最高级别。 与之不同的是journal的日志级别和DTK的日志级别不一致,journal的日志级别分别为:emergency、alert、critical、error、warning、notice、info、debug。 这是因为journal的日志级别是从syslog中继承过来的,而syslog的日志级别是从BSD的syslog中继承过来的。而DTK的日志级别是从Qt的日志级别中继承过来的。 下表是DTK日志级别和journal日志级别的对应关系 | DTK值 | 序号 | 含义 | syslog值 | syslog序号 | |---------|----|-------------------------------------|-------------|----------| | dTrace | 0 | 追踪级别,可用于大部分不需要的记录,用于内部代码追踪 | 无 | | | dDebug | 1 | 调试级别,用于软件的调试。 | LOG_DEBUG | 7 | | dInfo | 2 | 信息级别,可用于信息记录,这可能不仅对开发者有意义 | LOG_INFO | 6 | | dWarning | 3 | 警告,可以用来记录你的应用程序检测到的一些非致命的警告 | LOG_WARNING | 4 | | dError | 4 | 错误,可能是一个较大问题,导致你的程序工作出错,但不至于崩溃 | LOG_ERR | 3 | | dFatal | 5 | 致命错误,用于不可恢复的错误,在写入日志记录后立即崩溃应用程序(终止) | LOG_EMERG | 0 | | | | | LOG_ALERT | 1 | | | | | LOG_CRIT | 2 | | | | | LOG_NOTICE | 6 | ### 日志文件 如果你选择使用journal作为日志输出,那么你需要在系统中安装systemd(一般的linux发行版都会自带systemd)。并且需要确保`/var/log/journal/` 目录的存在,否则journal会将日志写入到`/run/log/journal/`目录中。 如果你选择使用控制台作为日志输出,那么不会生成日志文件。 如果你选择使用文件作为日志输出,那么你需要确保你的日志文件所在的目录存在,否则会导致日志文件无法创建。 ### 日志格式 如果你选择使用journal作为日志输出,且使用宏的方式进行日志输出,那么日志的格式为: `[时间] [进程ID] [线程ID] [日志级别] [文件名:行号] [函数名] [日志内容]`,你仅需要关注日志内容即可。其他的信息都是journal自动添加的。 @defgroup dlog @brief DTK日志组件 @details DTK日志组件,提供了日志的输出、日志级别的设置、日志文件的设置等功能。 对于DTK日志组件,我们提供了两种使用方式,一种是使用宏,另一种是使用类。 但是更为建议使用宏的方式进行使用 dtkcore-5.7.12/docs/settings/000077500000000000000000000000001476226660600160505ustar00rootroot00000000000000dtkcore-5.7.12/docs/settings/backend/000077500000000000000000000000001476226660600174375ustar00rootroot00000000000000dtkcore-5.7.12/docs/settings/backend/dsettingsdconfigbackend.zh_CN.dox000066400000000000000000000021321476226660600260170ustar00rootroot00000000000000/*! @~chinese @file include/settings/backend/dsettingsdconfigbackend.h @ingroup dsettings @class Dtk::Core::DSettingsDConfigBackend dsettingsdconfigbackend.h @brief 配置存储到DConfig @fn Dtk::Core::DSettingsDConfigBackend::DSettingsDConfigBackend(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr) @brief DSettingsDConfigBackend构造函数,使用DConfig为配置文件名,保存数据到配置文件。 @param[in] name 配置文件名 @param[in] subpath 配置文件名的子目录 @param[in] parent 父对象 @fn virtual QStringList Dtk::Core::DSettingsDConfigBackend::keys() const @brief 返回Dconfig的全部键值 @return @fn virtual QVariant Dtk::Core::DSettingsDConfigBackend::getOption(const QString &key) const @brief 从DConfig获取键值 @param[in] key @return @fn virtual void QVariant Dtk::Core::DSettingsDConfigBackend::doSetOption(const QString &key, const QVariant &value) @brief 给DConfig设置键值 @param[in] key @param[in] value @fn virtual void Dtk::Core::DSettingsDConfigBackend::doSync() @brief 触发DSettings将选项值保存到DConfig */dtkcore-5.7.12/docs/settings/backend/gsettingsbackend.zh_CN.dox000066400000000000000000000017441476226660600245000ustar00rootroot00000000000000/*! @~chinese @file include/settings/backend/gsettingsbackend.h @ingroup dsettings @class Dtk::Core::GSettingsBackend gsettingsbackend.h @brief DSettings的存储后端使用gsettings @details 你可以从libdtkcore-bin中找到此工具, 使用/usr/lib/x86_64-linux-gnu/libdtk-/DCore/bin/dtk-settings -h 获取帮助 @fn Dtk::Core::GSettingsBackend::GSettingsBackend(DSettings *settings, QObject *parent = nullptr) @brief GSettingsBackend构造函数 @fn virtual QStringList Dtk::Core::GSettingsBackend::keys() const @brief gsettings的全部键值 @return 返回gsettings的全部键值 @fn virtual QVariant Dtk::Core::GSettingsBackend::getOption(const QString &key) const @brief 根据`key`获取值 @return 返回键对应的值 @fn virtual void Dtk::Core::GSettingsBackend::doSetOption(const QString &key, const QVariant &value) @brief 设置`key`对应的值 @fn virtual void Dtk::Core::GSettingsBackend::doSync() @brief 触发DSettings将选项同步到存储 */dtkcore-5.7.12/docs/settings/backend/qsettingbackend.zh_CN.dox000066400000000000000000000020341476226660600243200ustar00rootroot00000000000000/*! @~chinese @file include/settings/backend/qsettingbackend.h @ingroup dsettings @class Dtk::Core::QSettingBackend qsettingbackend.h @brief 存储DSettings到QSettings @fn Dtk::Core::QSettingBackend::QSettingBackend(const QString &filepath, QObject *parent = 0) @brief QSettingBackend构造函数,使用QSettings::NativeFormat将数据保存到指定路径。 @param[in] filepath 存储数据的路径 @param[in] parent 父对象 @fn virtual QStringList Dtk::Core::QSettingBackend::keys() const @brief QSettings的全部键值 @return 返回QSettings的全部键值 @fn virtual QVariant Dtk::Core::QSettingBackend::getOption(const QString &key) const @brief 根据`key`获取值 @param[in] key 配置项名称 @return 返回键对应的值 @fn virtual void Dtk::Core::QSettingBackend::doSetOption(const QString &key, const QVariant &value) @brief 设置`key`对应的值 @param[in] key 配置项名称 @param[in] value 需要设置的值 @fn virtual void Dtk::Core::QSettingBackend::doSync() @brief 触发DSettings选项值保存到QSettings */dtkcore-5.7.12/docs/settings/dsettings.zh_CN.dox000066400000000000000000000170361476226660600215770ustar00rootroot00000000000000/*! @~chinese @file include/settings/dsettings.h @ingroup dsettings @class Dtk::Core::DSettingsBackend dsettings.h @brief DSettingsBackend是一个配置存储类的接口 @details 简单的例子: @code { "groups": [{ "key": "base", "name": "Basic settings", "groups": [{ "key": "open_action", "name": "Open Action", "options": [{ "key": "alway_open_on_new", "type": "checkbox", "text": "Always Open On New Windows", "default": true }, { "key": "open_file_action", "name": "Open File:", "type": "combobox", "default": "" } ] }, { "key": "new_tab_windows", "name": "New Tab & Window", "options": [{ "key": "new_window_path", "name": "New Window Open:", "type": "combobox", "default": "" }, { "key": "new_tab_path", "name": "New Tab Open:", "type": "combobox", "default": "" } ] } ] }] } @endcode 读取/设置其值的示例如下: @code // 初始化一个存储后端 QTemporaryFile tmpFile; tmpFile.open(); auto backend = new Dtk::Core::QSettingBackend(tmpFile.fileName()); // 从json中初始化配置 auto settings = Dtk::Core::DSettings::fromJsonFile(":/resources/data/dfm-settings.json"); settings->setBackend(backend); // 读取配置 auto opt = settings->option("base.new_tab_windows.new_window_path"); qDebug() << opt->value(); // 修改配置 opt->setValue("Test") qDebug() << opt->value(); @endcode @sa Dtk::Core::DSettingsOption @sa Dtk::Core::DSettingsGroup @sa Dtk::Core::DSettingsBackend @sa Dtk::Widget::DSettingsWidgetFactory @sa Dtk::Widget::DSettingsDialog @fn Dtk::Core::DSettingsBackend::DSettingsBackend(QObject *parent = Q_NULLPTR) @brief DSettingsBackend构造函数 @fn virtual QStringList DSettingsBackend::keys() const = 0; @brief 返回全部键值 @fn virtual QVariant DSettingsBackend::getOption(const QString &key) const = 0; @brief 获取 `key` 对应的值 @fn virtual void DSettingsBackend::doSync() = 0; @brief 开始进行同步 @fn virtual void DSettingsBackend::doSetOption(const QString &key, const QVariant &value) = 0; @brief 设置`key`对应的值,并使用存储后端进行存储。 @fn void DSettingsBackend::optionChanged(const QString &key, const QVariant &value); @brief DSettingsOption的值发生变化时发出的信号。 @details `key` 发生改变的 option 键,`value`对应键的值。 @fn void DSettingsBackend::sync(); @brief 私有信号,请勿使用。 @fn void DSettingsBackend::setOption(const QString &key, const QVariant &value); @brief 私有信号,请勿使用。 @class Dtk::Core::DSettings dsettings.h @brief DSettings是设计上为Dtk的应用程序提供统一的配置存储以及界面生成工具的基础库。 @details DSetting使用json作为应用配置程序的描述文件。简单来说,应用查询的配置分为组/键值二个基础层级, 对于一个标准的Dtk配置控件,一般只包含组/子组/键值三个层级,对于超过三个层级的键值,可以通过 DSettings的API接口进行读取和写入,但是不能在标准的DSettingsDialogs上显示出来。 一个简单的配置文件如下: @code { "groups": [{ "key": "base", "name": "Basic settings", "groups": [{ "key": "open_action", "name": "Open Action", "options": [{ "key": "alway_open_on_new", "type": "checkbox", "text": "Always Open On New Windows", "default": true }, { "key": "open_file_action", "name": "Open File:", "type": "combobox", "default": "" } ] }, { "key": "new_tab_windows", "name": "New Tab & Window", "options": [{ "key": "new_window_path", "name": "New Window Open:", "type": "combobox", "default": "" }, { "key": "new_tab_path", "name": "New Tab Open:", "type": "combobox", "default": "" } ] } ] }] } @endcode 该组中包含一个base的root组,两个子组: open_action/new_tab_windows,每个子组有包含若干选项。 对于"New Window Open:"这个配置,其完整的访问id为base.new_tab_windows.new_window_path。 读取/设置其值的示例如下: @code // 初始化一个存储后端 QTemporaryFile tmpFile; tmpFile.open(); auto backend = new Dtk::Core::QSettingBackend(tmpFile.fileName()); // 从json中初始化配置 auto settings = Dtk::Core::DSettings::fromJsonFile(":/resources/data/dfm-settings.json"); settings->setBackend(backend); // 读取配置 auto opt = settings->option("base.new_tab_windows.new_window_path"); qDebug() << opt->value(); // 修改配置 opt->setValue("Test") qDebug() << opt->value(); @endcode @sa Dtk::Core::DSettingsOption @sa Dtk::Core::DSettingsGroup @sa Dtk::Core::DSettingsBackend @sa Dtk::Widget::DSettingsWidgetFactory @sa Dtk::Widget::DSettingsDialog @fn Dtk::Core::DSettings::DSettings(QObject *parent = Q_NULLPTR) @brief DSettings构造函数 @fn void Dtk::Core::DSettings::setBackend(DSettingsBackend *backend = nullptr) @brief 设置存储后端 @fn static QPointer Dtk::Core::DSettings::fromJson(const QByteArray &json) @brief 从 json 中获取 DSettings,返回的数据使用之后需要自己手动释放。 @fn static QPointer Dtk::Core::DSettings::fromJsonFile(const QString &filepath) @brief 从 json 文件中获取 DSetting。 @fn QJsonObject Dtk::Core::DSettings::meta() const @brief 返回JSON对象 @fn QStringList Dtk::Core::DSettings::keys() const @brief 返回全部键值 @fn QList > Dtk::Core::DSettings::options() const @brief 返回全部 `key` 的值 @fn QPointer Dtk::Core::DSettings::option(const QString &key) const @brief 获取 `key` 对应的值 @fn QVariant Dtk::Core::DSettings::value(const QString &key) const @brief 获取 `key` 对应的值 @fn QStringList Dtk::Core::DSettings::groupKeys() const @brief 返回子组全部键值 @fn QList > Dtk::Core::DSettings::groups() const @brief 返回子组全部 `key` 的值 @fn QPointer Dtk::Core::DSettings::group(const QString &key) const @brief DSettings::group将递归找到子组 @return @fn QVariant Dtk::Core::DSettings::getOption(const QString &key) const @brief 获取 `key` 对应的值 @fn void Dtk::Core::DSettings::sync() @brief 开始进行同步 @fn void Dtk::Core::DSettings::setOption(const QString &key, const QVariant &value) @brief 设置键值 @fn void Dtk::Core::DSettings::reset() @brief 重置键值 */ dtkcore-5.7.12/docs/settings/dsettingsgroup.zh_CN.dox000066400000000000000000000050111476226660600226420ustar00rootroot00000000000000/*! @~chinese @file include/settings/dsettingsgroup.h @ingroup dsettings @class Dtk::Core::DSettingsGroup dsettingsgroup.h @brief 一组DSettings选项的集合,也可以包含子组。 @fn Dtk::Core::DSettingsGroup::DSettingsGroup(QObject *parent = Q_NULLPTR) @brief DSettingsGroup构造函数 @fn QPointer Dtk::Core::DSettingsGroup::parentGroup() const @brief 获取当前组的父组 @return @fn void Dtk::Core::DSettingsGroup::setParentGroup(QPointer< DSettingsGroup > parentGroup) @brief 设置当前组的父组为 `parentGroup` @fn QString Dtk::Core::DSettingsGroup::key() const @brief 返回这个组的键,会包含全部的父组的键 @return 返回这个组的键,会包含全部的父组的键 @fn QString Dtk::Core::DSettingsGroup::name() const @brief 返回这个组名称,它可能被翻译。 @return 返回这个组名称 @fn bool Dtk::Core::DSettingsGroup::isHidden() const @brief 检查这个选项组是否会在界面上显示 @return true 表示则这个选项组会显示出来 @fn QPointer Dtk::Core::DSettingsGroup::childGroup(const QString &groupKey) const @brief 返回给定键在选项组中对应的子组。`groupKey`子组的键 @return 返回子组的指针 @fn QPointer Dtk::Core::DSettingsGroup::option(const QString &key) const @brief 根据键值获取选项。`key`选项的完整键 @return 返回对应键值选项指针 @fn QList > Dtk::Core::DSettingsGroup::childGroups() const @brief 列出组下面所有的直接子组。 @return 返回所有子组指针列表 @fn QList > Dtk::Core::DSettingsGroup::childOptions() const @brief 列出组下面所有的直接选项。 @return 返回所有子选项指针列表 @fn QList > Dtk::Core::DSettingsGroup::options() const @brief 列出组下面所有的选项。 @return 返回所有选项指针列表 @fn QPointer Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &group) @brief 将json对象转化为DSettingsGroup。`prefixKey` 组键值前缀 `group` 待反序列化的json对象 @return 返回解析json后的组指针 @sa QPointer Dtk::Core::DSettingsOption @fn void Dtk::Core::DSettingsGroup::parseJson(const QString &prefixKey, const QJsonObject &group) @brief 将json对象转化为DSettingsGroup。`prefixKey` 组键值前缀 `group` 待反序列化的json对象 @sa QPointer Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json) */ dtkcore-5.7.12/docs/settings/dsettingsoption.zh_CN.dox000066400000000000000000000066001476226660600230230ustar00rootroot00000000000000/*! @~chinese @file include/settings/dsettingsoption.h @ingroup dsettings @class Dtk::Core::DSettingsOption dsettingsoption.h @brief DSettingsOption是DSettings的基本单元,用于存放一对键-值数据。 @fn Dtk::Core::DSettingsOption::DSettingsOption(QObject *parent = Q_NULLPTR) @brief DSettingsOption构造函数 @fn QPointer Dtk::Core::DSettingsOption::parentGroup() const @brief 当前选项的直接上级组 @return 返回当前选项的直接上级组 @fn void Dtk::Core::DSettingsOption::setParentGroup(QPointer parentGroup) @brief 修改当前选项的上级组 @param[in] parentGroup 上级组 @fn QString Dtk::Core::DSettingsOption::key() const @brief 当前选项的键值 @return 返回当前选项的键值 @fn QString Dtk::Core::DSettingsOption::name() const @brief 当前选项的名称 @return 返回当前选项的名称 @fn bool Dtk::Core::DSettingsOption::canReset() const @brief 选项是否可以重置,如果可以重置,在调用reset方法后,选项的值会变成初始值。 @return 如果可以重置则为true @fn QVariant Dtk::Core::DSettingsOption::defaultValue() const @brief 选项的默认值 @return 返回选项的默认值 @fn QVariant Dtk::Core::DSettingsOption::value() const @brief 选项的当前值 @return 返回选项的当前值 @fn QVariant Dtk::Core::DSettingsOption::data(const QString &dataType) const @param[in] dataType 数据类型 @brief 选项的附件data,用于未选项设置一些额外的辅助属性。 @return 数据类型对应的数据. @sa QObject::property @sa Dtk::Core::DSettingsOption::setData @fn QString Dtk::Core::DSettingsOption::viewType() const @brief 选项的控件类型 @return 返回选项的控件类型 @sa Dtk::Widget::DSettingsWidgetFactory @fn bool Dtk::Core::DSettingsOption::isHidden() const @brief 检查选项是否会在界面上显示 @return 如果显示则返回true,否则返回false。 @fn static QPointer Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json) @brief 从json对象中反序列化出一个选项对象 @param[in] prefixKey 选项的前缀 @param[in] json 待反序列化的json对象 @return 返回解析完成后的 `option` 数据 @fn void Dtk::Core::DSettingsOption::setValue(QVariant value) @brief 设置选项的当前值. @param[in] value 选项的当前值 @fn void Dtk::Core::DSettingsOption::setData(const QString &dataType, QVariant value) @brief 为选项添加自定义属性 @param[in] dataType 选项的扎属性数据id,对每个选项必须唯一 @param[in] value 选项id对应的值 @sa Dtk::Core::DSettingsOption::data @fn void Dtk::Core::DSettingsOption::parseJson(const QString &prefixKey, const QJsonObject &option) @brief 从json对象中反序列化,并设置自身的值。 @param[in] prefixKey 选项的前缀 @param[in] option 待反序列化的json对象 @sa QPointer Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json) @fn void Dtk::Core::DSettingsOption::valueChanged(QVariant value) @brief 选项的数据变化时发出改信息 @param[in] value 发生改变的数据 @fn void Dtk::Core::DSettingsOption::dataChanged(const QString &dataType, QVariant value); @brief 选项的附件的额外数据变化时发出改信息,可以看作这个值的属性发生变化。 @param[in] dataType 改变的数据类型 @param[in] value 发生改变的数据 */dtkcore-5.7.12/docs/settings/index.zh_CN.md000066400000000000000000000102241476226660600205000ustar00rootroot00000000000000@page dsettings dsettings--dtk设置工具组件 # DSettings ## DSettings:dtk设置组件 [dsettings.h 详细文档](dsettings_8h.html) 项目目录结构如下: ```bash ├── CMakeLists.txt ├── data │ └── settings.json ├── data.qrc └── main.cpp ``` CMakeLists.txt: ```cmake cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 project(dsetting-example VERSION 1.0.0 LANGUAGES CXX)# 指定项目名称, 版本, 语言 cxx就是c++ set(CMAKE_CXX_STANDARD 11) # 指定c++标准 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 endif() find_package(DtkCore REQUIRED) # 寻找Dtk组件Core add_executable(${PROJECT_NAME} # 生成可执行文件 main.cpp data.qrc ) target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 Dtk::Core ) ``` settings.json: ```json { "groups": [{ "key": "base", "name": "Basic settings", "groups": [{ "key": "open_action", "name": "Open Action", "options": [{ "key": "alway_open_on_new", "type": "checkbox", "text": "Always Open On New Windows", "default": true }, { "key": "open_file_action", "name": "Open File:", "type": "combobox", "default": "" } ] }, { "key": "new_tab_windows", "name": "New Tab & Window", "options": [{ "key": "new_window_path", "name": "New Window Open:", "type": "combobox", "default": "" }, { "key": "new_tab_path", "name": "New Tab Open:", "type": "combobox", "default": "" } ] } ] }] } ``` data.qrc ```xml data/settings.json ``` main.cpp ```cpp #include #include #include #include #include #include #include DCORE_USE_NAMESPACE int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 初始化一个存储后端 QTemporaryFile tmpFile; tmpFile.open(); QPointer backend = new QSettingBackend(tmpFile.fileName()); // 从json中初始化配置 QPointer settings = DSettings::fromJsonFile(":/data/settings.json"); settings->setBackend(backend); // 读取配置 // 该组中包含一个base的root组,两个子组: open_action/new_tab_windows,每个子组有包含若干选项。 // 对于"New Window Open:"这个配置,其完整的访问id为base.new_tab_windows.new_window_path。 QPointer opt = settings->option("base.new_tab_windows.new_window_path"); qDebug() << opt->value(); // 修改配置 opt->setValue("Test"); qDebug() << opt->value(); // 获取所有keys QStringList keys = settings->keys(); qDebug() << keys; // base.open_action对应的组 QPointer group = settings->group("base.open_action"); qDebug() << group->key(); return a.exec(); } ``` 编译运行: ```bash cmake -Bbuild cmake --build build ./build/dsetting-example ``` 运行结果如下图: ![img](/docs/src/dsettings.png) @defgroup dsettings @brief dtk设置组件 dtkcore-5.7.12/docs/src/000077500000000000000000000000001476226660600147775ustar00rootroot00000000000000dtkcore-5.7.12/docs/src/dciicon-tree.png000066400000000000000000001626611476226660600200660ustar00rootroot00000000000000PNG  IHDR~ pHYs+ IDATx}wݶyQiԭ"٪e[݉ޜM}&qzsz}ْ&MOljK*7[{n| 2[$p9 *ĕ!52΅Ih利Pm f"2czSVΒa.XטMQŖ^ek 2᰿`UTP{ uH\3g @!qpvgDIqnr lu ; 2hJdj!!NPe&GhȔ) {̜ys/Yqَ0[`Hr+&\e'xEp *VJ( n?!IrmMaפ`(P/[eJ_HUY3KUQsoAgRW zʩ! V Egt&.^@f?X$!% wᲕ𓵃qjjdgaT1^4KWMr \DaҜY]`d =9CIj?¶4$}p] RdȢ9m2('îȬ8[6<7NsU3{N5yX&V`L3jeMX9= cBYY@w[B}u-DC-O<ƫ؉50|)MJ\mokL%- E~"MgbT+P)w[F2/DqnS:s砐g, [L*)!2 Ҏȹ,E#g1qj\q)JyqΙ ED! b\hd#O tO;0(Q:M5Ir蓍"'I%syjt%3 jU π1&OE W𕄢?U 9뢱2SوD@6gpM-xr[p%aѨ͂UbD||h)*b` ,8{ > mY3.S>/ũ*@ nRƦE\YJx|xFH1#?rAb]SZ2+6Xlj`A30؈0v$˚hqPT |?`#Sٴً!&( 6r&`Pߊ*E4r9,YҶ15>xnP!hnܷ\p΍[>?֎/}^MщL/O׈xg)'Y=1_Vu.?F0"`4Mq.X *ulEBɮfIu;ݒ!XBs]rӥ;zziCƆ _dz쩍?>O %>pjIş:DVF qcԨ*n2-U\E #^%nТsnIFt&NӁI.Qċ,XNhRM' YMKK:"@HgaUIQ,cJpZc# 9 8r@mRڤϵndj* U=`.d7f@7-a 665LOmWT*퀚3hSPHG eWwwu*i`*Rςy$\{h,8jsqo[#j!t&hA]PRY)^W)Gjb1jW9f/;紸6Xb/pBdN{.wY0NN3đD!a5NaC=xn1Ճ*6 wUcVOOpy.>'20GLĠ Y$G@25g l܁b_(CmNꂣ~~sv  *t:+k6KօdNXd2tL1JvX~M=d+ -I4 EؓQ i*ebɺJخ Y;9nk'7v1]+Ӿ.蓜`aGR Yj.*NrƮb;_e(jpG3R%,24)j'_Dzp,q)"]636P9.n1&s@B7ڢub,Q',zlpy0q8+q3OU7tԈwHKηU!mޢȬ%ۂ2bVdp6 {ԑ-SYRsXb^A.q N^+#Ɓ ȵZ6Q̥ؾ&)FKBhE7:)t G @di=6-Y(b3 sҘK\GN`sdLSd55*[}z00T,p--nTeyEX8']Ŧу ÿoH1_gRQQCமEL¢}` J[LȤ vŷN|_L/k@Uu[aox1jv^p/Tuӥ_yͫq=[>G,L~oX2tY^H/jlsV FXwb w"MqQ `XKb e$* |U҂Q8AGR&GOē*C!EUF_o$ bH/| 4qͷi2DrXS#TI/pw셭{6 ^JЧE<|\**9H VpI  ?&+ {*lqlAC˦ֹw`eji#5*(j*(JvXGb=Zft]Mݲ\gTUٸ/3E Ālgܼh)9A0CN-VcY¬jz,D>;47^t(/_J"I?0w%OnS}Xsɢ _ͿlmfLXxwl~PkX?)M9OLl{Ų&SïB g]?oomzՊ;e$?)]BX8K<9:ek_1^SW=={C~ _ƩoXMFҊs=o_3gw].%}َ?77Nv'/YoȱtC˿yvz @Mgjqy߰pl'(mMF!嵺mwBBn**2[h|NtZhBhcVvݿy'/ ¥l&R#9%kN8?}+n>!9x϶M;Rwe·F:FhK-l0`-[=m*cWwE'1e{wزKQX*HNjO6Zt޼'6L4ԹGm~w*{dI|dzt,rL{ PX-L5cg-U./z, X33zE|{ S pؤpe-18p1n`Pad˦Lꘇdݪ,=|rRPs1{p/rѣok)Ha޵ܷHHd@T>97x xR|Jm߷H- *7tiZCd!P!$dvyn(lieVDY#ɲ0 u~']Z,O&\2ц',4NYbmZrC Pn:RAɄ]Env?kV|bhc/}g$vFk~9:;t@U5K%j]rUUU5kszXB,UU͝UZ@LjN;SU2qcYrx(V"=`jIb _/3y/DhSJ@^[r(5鯪Z{/#B|⩡L.ԕ?dij!ЍZ?ذwzΦΙSVu SUE| Y[fȲ?;HF㽭MScѱӅERC\+_C$Z#+4Tr Mu4O/ARkTTh'|"* ĕA+sns*KʚMXEq塹qvE2,r9TϔМ|=HH!Փ.QOuRBXЉ KyfײhLpQ|~_X]-yMKcW41e¹>_8\:յijK㔋/xoI`!/h{E/k#G K_BQ:=u f^;Z57N=mso$< y tޝ09жXIQ'6=C=©\F /24 ]a1lɈ9$(Mx+N ƅ-+2he VEU6}Fg67"TY"ŝr݁GFaw4ᜑ]kUm+)E|1U7nEQɍ6u hg}ZCL 8w!DtphS5ʮieb cfnU\~6>PK\eHVMi@8/0]j0j,5:`-ZGbx`bۂĕl64X ?7nwm%j~$,KXGU7d %!˦(2Dkz-zpLўDm%tޖ @gF=:%")c $a{\C{cf@+"XPWh~YXȦA'-b$ :0akǶL+Tn:ui 8h,{eJEXqg7Ǡƌ8&=`5OLB8' j"]?ʢmL\OEbC TrQO*T0~>@oLcȤ ߾pu;ls> N@!U|\nVE/X,+ؤg95`r, 5eյx֑'*hVOOK06 ڼ}ӵRW̡z=ɨ8PfhnMTز`vF* -MQ@Viͥ0Muѿ3mX<ϱͫ$1Cv}GplF~T+Ci}ҐɴYIks4ɘ]xRB^/b XgkH MfI7l\@{0bc >y8_AD/;r!Tkw0>(S!!Y+ޥu&EjUs4f?rA!"$&M8զs.N e1a B!|O"SШ+4Ġ$Umz١eOdb.ے=--C+BYM _2N0Qi>.cDCIM(&Q*BYXS ꓌LR5)sZ:6Xsd-C HhPkUk֗~LJc4{3tZy!Κ7Ҷ]/E'LtIմQ>8C 5 )ǟmKVd&e: IDAT_X9xeql-sH)bC8̷d0{

yIlԈh!x O(28}SIjc# LlΣ,S!H/#OK!=/<ܛKߑ/tT 7]&˒DG^~Jza֢hIpZj~8cNg9DݴQIPu!d:0^4:̸E:LB1 0T 2(H^ %Tw0WH0; Krrz/H_:. ^| :0wvA-I$l$Qy`N`biS 97% }HWu'>L"Ԁ8$ax ( KiX߸hzIqgwZpjdD.|RBqQaY,.ޢV!8}7P-23Lo"{"1Ks\ @7͔~-t*3h+`PNtZЉ+H j ePF;2ExK( Y".-Tc3Ϗ" >/NV9RlvLb6;duZw& $Ad߀ATqyZvdn.W)\H^h_]60>#i(9(m1-B_a:8x(\!"7X-4]-pR dW v#b`.eLn}UxXhp_sN 5z\ZY$Qu RlMM62jf"*1XB?{L?*U@41 d"0'H$9 fccCwТ-s"d/I#Ʊ}v  Z"j?D/DA6pB-? N/J55 `sA!INJ>h+P&` gKJO[ ԡ;Veog4hp[}j*4 kq_!8K61saqgTS廯r TcEb@䧀(lPG: s6QhD&qmáǣ97Ϲ=)D9r1Psl>U6-EJ' sqi&DX1ac$rzbӢbUH+ȊLQa@qޑJ$IMVctqjspP%*5eOz <3!9w[zʊEБdnh:7Efw+AIHqCtH Dx˯={Z+DGqTłN/%c)9X/U+6 N~1W g sd`SV m:iF(D%m40 `LTMɡ#\7U!!E^\c`wIGںRigT@K?/{9`rDwޓk{/ }qoAQ`>\eFy\.rlmt3'4#y2 C{hJ=X=*`dz'sRq.!|,"JZTW3 Rr@\xEt5D߄>HI:򤿽xV5|>:/_{%pzSM %Ov<B eb[~ f<@ ar#WA*J2T [r"7cDZx'TVWԬK0rwG5z}ͽJﶛ/i\tmN+M/YCC[^DaYeIFF)'oZ$JLFj+Sh)5 VbX"ۻ06] F%:t)6´*DĠ;ʡ" 7Ew(_CթxWkdSOJ.s vְ 5xp~f3MLSO FG.rHɚO ܡCGL#JV#HUzTω 4dk?\ ^!uNc9% 8`1rΧ!fUdZ< թ Hͺ!0eOؙe -gGKN^9`ŽͬOn㋝ \Ab ٸ@#|e#S Δi;/Om)+F/Ibچ/P_k rp'Ht-oR>ʴSj7Jv_HZ+&rG| pZ#>qsЀ{ta pL&G'rLgR#RM0(RI/Bm2J ǝrpKU)N$;FRj`pt4}&U3oP/>u(CYџkVw>")>3\GB|nCnG_Bz@QWIYחt77uQW|JŻD>Ӱ@^`+$p:h[^Kh!ߵKoi}Di^@W ƻh8LtTx ,hXTתFߍ+GS99M?P/Z``o+q 9|HC x4P~i.i$ oRP ͠PGÊYZZ8.Ӷ[{2Typ\b&|ل*`,wҐ%4HDX1oQi8|qsq&f\dJ0&X*)ͥ5ejK`4 Jb W"lះ??쓑C?BY7m뾑m\ڏJ=XpC٨cr<x_c;"+`*9 ~~DתlTsԣ87&V|65#WT%зmP!n(" ̨[;3U3XW|朗ё}erpp%F`JIÀdE&-|gd]*zm* +Pʌ[#/: I 7+Ҽ! -wHwE?,/\aۣ{CT0۰yo΅; 6;)RJ9+zF;=yw"xc 0Јj.W&0qgB#MILUয5䤥羷iϟ{ .F.Uٟ u /xGJFҌFUCR@ y2@v pҏ7?Hɠl(08:RHqhO(j}ȆۇޙJZz*xTA m8dzjK(>()TBB?v\+Լ[_o^5r2(0vOdS\|F|cL< \Jʎ6g%m}o# ?sP>RFƵFwtgq#+`fEȤWNPmJE (ѵzh?5?z,6;c:)5%yϸ*:u÷Q6etG (Y)5 % h)-M(Fq ; We÷P6u'"eL 2(Y)9 4 Q2ҾL }/p}YAZqT+ *\]U*1HVy Zb6ү52bR+D^B03B`Re[웆mWłˑMJc4[` n?OJ y dW9IA93f*?d:)GJu HQ^/= *~@ʌe~@G 5 <_J ș1FCddr ;8MRRe6dS66&j14-wLbTOf#c*&2$4uvb6LW̴򄭜,Ֆ}#1|=>ii;':ᒘen]3O}?rZ/%p)?2gl-c3o }M5{:hn@gZ͹(0`ę O}PxS36ֱ7El3rIWjPz@ | GBK|#%t>k^+ |Q]滓] i㼱9o̅;:D$ f߬:R1xz/чtKHINɉQI FbNHn$TmU?.F7%Pёs9I)xKE :z/v~$ul-mi4v!(%{w}7|S$'9o9}riZ6AG亜?WXhn_OE.wyf־R6>^׽ Grr'Ԧؼמ{9NqY:Cc4}y_ڴw(Ƞd"Ǟ58s{@Em3@\6 f\^D9 B2Ĉp@"|ReԋzO{a7>'ؗZ:H]pL;P \z}P@.j`@Q2/X3RMeR rijYGj86--§Hk $$YنIKrO ̲ D4Mu{;'"@O@);;x"0u+ihRJê/Pظ_1\;[8:x|`Tlt1R+H}C W1^qd:~yCy ;^H>ddLciM~)5T.dd@JQsbyUte.Oua(5 L vybWY L@وۯYArc!hp %T֜i5 (44 R]~%;R(Vz{P+b%]R-9>bsBS ş4&M-<+*?U[ VĨ禘{ȃB;OˆWtl;l(xs0v"D V[?0*[N)897YVb nnB0z 3eHs 6UnM_^n&xT>˸""ꉩ5ټp.Co5aHV`raoY @aXbԯ66u0 *rRlt*:d@ (&`*,1V,a渵 V)[LZknI/J[mY5 7ĀI5b Ք2&d xyInkw{/A|ky՟EͼN#: 8.8btMB)%T0 8ʃ w.:S.ZG=<# ~5 ,ftU-Ks`17G&YfoKSʤcrelTfS%TvL&\B҂75LziO=&-]:]tl"EWvVg !n0s@+6La\ jhbC R:Wo]Y]*mphĔ &-wiVt{K9/'H\B= |:YNift:s8 d| f.ۢL %SJGR~,z.k 1WZU (1ט2y(jn$v2MW+ksjj \`a)3, ʫhCw nb@ u8ԛ%t gOG}ti?:o;qذq⠸ j_#= (oZH&aaMaMyzP:?>.8oON Ɨ t ![mJb( O:D[4@U-?5CFjZY:kyc]JM[O3$k!K@ rQ gūj7d*6f5Ȕ&6tP!Z1Cm$wVrIW Ѓ]SW<"h~Y ԤgK xH?|d1}(RjWr%@cZ1b gE^Ɯ9`X 5?|ʨU . eL6%+hƺ2VxGSBL)%ej>+`JcC:^A`="!b|u΀pij`W@RYfIůjP9C]Fx~@P4,~weL2”`VХ4pv\cԁ̍'"InhnSVVT?yKChLN9:b?S#y9v' BgVӲw6 f# mTkw i @4hA$KV( M. .ZʨP 9oU$μqt xoF9 )1*-L~L`8BتV `1@Aǂ}\ӮmKN^>xlسS,.km TV 231d(1"*+/[ϚR+QJS=Cg?&{}1*G.{C*f\"贫"֣lr%HL^ J.zٖ]HDC GIM<|jCgڗNI 5eRzT@xTtE  8XآCH%ޮ2LgP|ֺ LzKI哏9relR*ӬJCg*+S;}MRB(}eڞtkpܶnn=t䋽~,zΗ_Tcwp 4:w2 K?3jCMU63bHB?{!NS8e]Ma!5!G A7"@5I= c-4mQB+K$iW$',nu&`L܎^ (9PU!Y GσH,xa)d衇#P\99(g,f;:URR߲ UwIJVJsy`:0 E, jXf,'(NAωK_ĔIt3R6Jt˜Y7θ!rl-&(H/uk.ԑxtg6ƽؑLTљ7rͺ5tUH=ы!*TCy@>C 﨨_yτ hI:&%2ѝ>k:y u\xc/[}ƃ5~ )o w~HUMGh+d@#3nx '.0_omuU#^xwι*7Ecqh :Fg\LlS9ޓdh;L,zz}},Կυ}ˮgucSyoOLZ9z|m] G~ Ԯp5*`r, a|bܜ G uUiuw(; ն zYz o\;6u"_q*5b986kXU 7XLU(kQc@{/nݺRz,1SC 卾#6oڳltJFB31X}PV.x ;o:1|?"gF,Sرٞ@%E:UOZXԲXՖ< \WL^뾲y}Sp::e`чܶwÉF};M#}Oxn]`&d-_`&e(A$rg+.6ye6>cbT9ػӉꏜ@UB;'lh 0ϳ)~5}g.k^l~Frz,Կ#wCqo%Д2l +0 $%b5؂B % Ӳ>7\c?j[7;D!UEN5{:0t.U`F߭srRR6V卾d*PؠfW`RF3#`~#p/pf- #ƍK]4ٶpx-P{c7Dz^lMDuȌf︵Ghjo@|*bF7xzoM]=8R6>qWB; p(B;6':ϸ)ԿHlO +;#sn\p/ײ>>Ϝ0 lt&E,0:Mx\ ylW\㉵Ix!4F߭!}s}J/*n-La'4s _}Q1^uybP}3+ (n;Vʒ Ě 64 kp"n?ue"͗D?KZQ]^K`%Y&l3${b2H(셜K7_BJFf7dm.BB~"]0\M.-6dgLQY %;Qח@׀]^+p%2+A}U͐`M(s  Ug=V 鬹Jѧvy<.st&Ҳ91:'f&̽z䡚@h+K@}TUQ]}?l>5G=5WYWK>b%x RLj!W>+fvlG d@Oo^kr fNhC>]:;ĐG N4u^"5̫JvMXh[ɡ=Gv+4Jq|۟|ġM,iWFBmz6y| 5FzٴmVХ *`SJ?W-3&bge?2vr֟.}ڃy(BMp?[cV/YPD{}څf4?am8b5`Sv\\_D!M =iW7IӯUotڕ 7lS{.3>i(k[w^ʌ%:/95(zY䱮"7Ne_ D$B/GJ :+ U =J yF٤/T%dT\3t1PɎE{vuSBcӮhg?N_T$o_H7vu=?xI{S#:7|7{ѧ濧}O8(ENc(1Ļ Zx t.N99H2sx_2ogQ.N6|hxmp;P@ȗj8?vJʥ@S>Wok+?t̆۹"]B#A/2 ]WQMvEcQ{P6 PxEU 1QDZ<"JBȇˣ)=ꋝu]x!l;WNʙ1˼nUgS%%+%s5LV@1Wc.Q!H%B<2#K^䕥3HI7{FUɟj=<7e\y$ϼ%jOt,ukU߲ y#3n(yK5_:GN?aD!r!j?DU':ϸ)Կ}J% s4^7̹}pD_?ҲOcWCѓ/fPr'_h}ȃx4+]u8Ϭ9f+fZycן|be*b ^Aת=xpܢpۍU?Nq'By n /pA$P69yݗ] jbGZA`9\AG 8Cõ-q5]0nl]? c>oQi_ H~]&2c%CĢǞ糷csP[?">X]uǷ@GpՖVPW7\j–?j_m~@JF nR`Cpu]*0F99H;o8}B ;::s&l>$]uDZ@,B*0m]ȻwE^BI#3n;Cn9g}+#<\mڮU{mr=J'op[#GRͳS-sSͳT_m=]}<0z%1>\ .m,n-mm 8'(5?:8݃ߝ?)e6|5Կ͜uǃ@77n5.6NJ*A^C]°ѷf?cWmi*..^'W?h$'z^/!lنp]^K`@x]mP´ɲmxpBN MZ*aR9:Ẽחʢʟ rE %Pr+|} N6O %x.Q퍾;2'^yt%x3'_0,T%eg(:` *\*\*ޣy߽?fY /t/ ޸=x #U y"UyfE7^.HT25">9pk IDAT/>~ϑ xF,WQPUEUAQ\w2WG}AP Gy0^Qa.˾pz`gcdRׄE~_T߶ ;~>; >9`Mg\ O>C攴jv^2wڕ?§d:Z4v;C'_tG}_6v d'zlDjy)~!4CuӮ߽),׽x[gu]?>=qw iZcVIqRlLUT$/I+#V%S+QC ր/<8z,hGdIP?{wVyy΢]eEeK;v!_@Z2v e5}q[..3m)G\k Z&  MMȐ=$qYeڗssbLl˲-ɖyx(zsE>(gNiG]ۚ!AVOJ!M>*>Qc쳉8EfBSq `9Nxu'?mgmott $Ԏ0yIMn@N҄k R`-EE5c[,% uRjQo)Zrѫ S8N0NvL Eܲ5+O) e)^cL91 f jPڱE6W;6Xϡk5ϫxN%4NBh}]ܤwᰬn p'Pz?Bq]'KCA{G6@?:y77_pڵBWݺ ZKW}q~6mRƧ+K7RQB-c<[JrL/E^]ă  ^Nvmuw^x.($5om?ks 7e[?3wsP}ldȐ 1)sb-GBS!!k7  7Ŀ0  ӛnn9O ! bz9t}[7h<'V-uO'_@K- i <|W>\Ì#*!iI#9? $@B$ $@B$ $@^=][q냒]Xg^B 7*"3z 9F:W~)>v Q{ eRCask\okG.t!*Ei,ͿEz>xvzJȺ~yS iLU;">2LfDHL)ny0yh׸/ƌ^g 9'H8_~nO aSyI@ $SsOSs/ǨDv[e9ͨuW!QceI }0v}PzCk+վΩ‹NϽ1spl4%c3pXPte#АѥJZ !5fB~N(*SԤy1faQ Gv]~K|c>= '36S%KAHTpR0Fh$3,(JD/!рckcEmurϒs2+03קnN rު{˶6v ~gHXx1Q36+4ƫ!yGqnȊGM﫼HQ cL{9JKV.y fyJ '7<0,K%h ,] ,=՜i˳̔K+"TLph%| B\QWmُ4:..O uḭǃ0W)C :,+m+n L ̇QA%")CܒLW!!wBrliJ:9+ҩذ巆3 C jǖ+;NK>t 0rYlɖݗ Ci@H+V~ye篾v.*ZJQ X@V rB\Ecբag|Q)!@>ȓ##$U(~7P(2 U NGhFErόB;#$/HQ_3 Ki~Ҷb| G'<ݴz 30H7z  #imޥۼw>(i޵P6 c (A| z 9F:W~)>v{&"L s%f( z[_>&h[;r!+ YW)N3di (SWyƫԣWBֵs+@BHHLyRXŒٌQꭺv%b:ڧG4L!,ٶe뙗dug ;L mbEh[~dT,h i<3\>wÒ"D璾a  70QpbбԱW7xb5E8X 0P(0'js Ub<6+VNlg > A>9 $ F)c_c`2LfDHL)ny0yh׸/ƌ^g 9x<U%ͻ}T ;>~v{_yW1{[cJ.rt^LqАJwl[_L@ $(S8%Y=/#/-=]A oAJbjkj9 `. H@HH@H1Aӿ{`lp`QVOfYmNS}T-0-B9o1}Q+|7cC Ckи cgBBNae3U7dY67&8"c3!0&Fڧ"{?4!Zw>22t$/U7pz< kҩ)ӹcT`Mm;W޲fPqFyK+WO>(=ݡ5OFj_Tyq' ywO!$so7$Mn >3*ָ.]C64dj{gt郒B~P*DF BBzĤIrD}].u F)qH@9%CC@?Srۚ[߉E0W"XUzOڹ+[^#$̕DOt!sH@Hte!R^fB$ $@BB$ $@^=][q냒]ۅXoG1U :-*8%\۹.lqL s%f( z[_>&h[;r!+ YW)N3di (SWyƫԣWBֵsR(!!2JaA 3Ndd&(Vm; 1uh# X^&yl[Kxp3?yo~z-`_?k*_N44KN3У>wÒ"D璾a  70QpbбԱW7xb5E8t㡝\BÔ)|8QV/K'E $Y*_wb;SDo2!P0:GH9Fȧ@x^yg2ay7c ET`*8f( $_y95V$SN2lr BB tln{\ﭾWXBVyf>*G))%'.y@ ݭ)~}UnwT 09NzmNj>sn}ϡndBB8az!$T>FBBL -s/dƷG9FZ=eY:M:QE 26r UwtEMAg^  7 yBjFfH!!0ܲ{*  EfBaLεOK7E6~hnyC|d4d]e>H8_~nO aSyI@ $SsOSs/ǨDv[e9ͨuW!QceI }0v}PzCk+վΩ@ϐb3,glV iJWQ9BR r w:Wy;#EK#u&h*rrS ]@"cs6N9nyrO^؃^B.QDc`hp7t7o`4N^ef_MX}eCy@њMԗ?L ϪGp4FHb+`$ $#FHL/C:23, %@aCHT}!`F9. $@BVWYXŶ5j)i|շ%9J1h+kvl֪݋R Y@)g5ׇ"~ʭVm=])6G^kK) iSpڱŤwPBSNK)<uXV WDτ mm:MI/} *QI!0@v-:egBBZشy^>>[:SؤӔtC ul܃ElТwۇmu-u֮PakllyÙL) e;$ĤIrD}]Jhc敏o{sY6RxvrU^dXS D ]~hg\n[Sxks;XU_^YoB&{L+6,E91 n}s?#L#k߮ ;J>73@B^H_nėBp#|ҟAH sLH@H^,7b B$ $@B-ibW IDAT$=2I4숷Wsy;K-7Nrr[cM̈́Ɣӭםdpo/v9F@FgHW SAT 4>oZ(;Hki2& w9BH1)EZQmu8At \>?R_yQt htZ?4?|ڇm6s= }Cg !ZuAk[U7})^$44Vhr=MRS\k,WȾѤS]Z _”gUuyo#.} \śj"x-u{6?_wPBv?|w=$jy1ek]YRn# _n_穖&ߺ Q;;I bR_nq{ٟq5?z㩽YXcD7>Ta_In3e WbO%&p_lD}0-q KVƔjJcͯ&\CA*Y^H_qT=Y9H)^hD a. d\a< 9E. !0pƥ*]34om?ks Z^B9T(s3DHtIas "$d @:GK1K_ʹk%H>#$@@ܷysbm\t3y?0w+ G  4ˤB T  3G iM﹗??^=][q냒]\`/kͲ,wM"ͺ {5$U 1vLF9WahMY,=՜‡c CkиT~d_sRa!W8i$Hh#3Ǽ”WBBH1Z׹CO3R^L+)LεOK7E6~hnyC|d4d]e>H8_~nO a뿣\%+׸/syz<4tg*)8vQ:>6?6Eeu6M>”`UE.*\HRYcvsBY;)B[Hbk,5nzQ !$j,sƮJ|wh͓cI(Vm; 1uh# X^8U!$Yn8Bѕ=ThCCwF>(i->׸ Bģ8.99LRs014us7<,i-3 t@H(,A[HoݗIO'4o4BJ”BT/aS2BRZaRɎ`*"HS3* {8VǢGYm&P%KAWS9IBubx2%'j3BB!$plq|흢}rQB#Q$>CÉR0W5ZzT )*!UNU*فdT8q5S!L#9v>:#Rd6\P(签wxcW&ʜgO o5vU{ QaNWxULg#TΥ¨bq̰S$.<2})kS,酐oƮvƶ0NpmY}3R4R\)aז''凞TƶP%j>IAƉKVݣ9DSK,N,*D-7nFG”T*a ]򀬱l9Oa״1{MZyZM_ G9FX<'lF׸O#pG|X|" ; ;_4 #>^5!4\|McOJW9…U"J_i(jwT+a#_MX}15wE6}dnٍFGk6S{Z1L lxV=ږFXywiz KZnALg*{` V!h erS^^\RINؖqʃ1u5O(^㾨?3bz !$>^| ,i޵ox{_yW1d.` Aj8>f>*G))%'.y@ ݭ)~}UR{ !&G)QϲQ}xgn٭94 BHLlS^S\9s   Gi`ZW>XجUAgs;)ȇ !a(6G^kr B\1y4밬t̳rH]WJERɇ Hr>*&s~@t566<{!,(KJhc敏o{sҀ\}=m?ٲrƔnl $ jWv{;-%(LcRh[0 soWƆ!GGˇ *q1]>d[+ !iI#݀AH=O! $@B$ $@0Aӿ{Քk!˹GڼKy+4u}PҼ+K'eS`YVcCvhFyoޚm*LW;S&œ0SN }NjD U>epCH1A5Oh\bЙjy싚^ΐѽl R-kJ\+nn-6Yoj\CGV5' =rJbTF!JQ!f`-W~âw|Uw1**R`+X*!L̇]ѫiS4ɢѹ`F-s1ȶ]  o )!l`wԞ+1CYd{͝r#4tg*)8vQ:~١A4SËV[_W|NB _p!UHe9R\} *ogqﴃao!W޲fPqFyK+WO>(=ݡ5OFj_'[uK/t֡O4CÉR0W5ZzT )*!UNU*فdT8q5S!L#9v>:#Rd6\P(签wxcW&ʜgO o5vU{ QaNWxULg#TΥ¨bq̰S$.<2})kS,EBH7A[c]Mc['붏x)Z)հkKѓBCO|]c[5v H%{ 'JbTxg郁["EKÖ\7}#ZTc#aJ*NŅKV.y@XBVyk霧İkS&J-y@<-/酁#k,[iCuk\'_tRFXX|" ;ײC"iGdQ}ȽkBhʛƞr@ BE&Z)QV۩j]MV8F!L)-BMcj;3Uu lܲˍl/荧fmL6Mz^gգm)^j,{W $^KK(\wb:ėPG fأ+汲x(X xJ& PESEU%ͻ}S_|uO=㋔4?>38fzX0p@c014vRW)KuBrBL2Seۣ2ܲ[shfؖ)ޟr ! !J|qP,wL{P !Q|nw=WLҒҶçZ_D}s3mk !MWzV.}PǚB9-)ƥ_4g/6* ! &#&<=KSVV,巊wL$MԒ2 _-[tFU[xʛ1)?ioYQgӉ{@Ŕ?:ҁ/u֭k^ȑcR轣xͫYWqw>{I(JR[qǺ[W ζy X"[k}7Ƥ/ ^7䥩*$kYU~6\Sv]mO$bRwo"EEK7H{=x:/vklxXNB,d9(ҩy}UꞋv ]MWmxh8BH 49 !qz)IŶm?B2j$?#$IPs龡OQ1Luq1lM:Q\v]9pkنaω:9F=/8ؠ˛B JԓH˅yb}osOk7$rso{|,82lErEI p,BCʸPɥ Zb[_JRa(:&}"# "C.}RjQo)Zrѫ S8N0)Qј??,oXN | 6s{uK٢U7,yy:x-۰ y^s0"h,^W/"CQ_ZU!嵋o7:M pt4^pT 8OPmmNSPuOeu5kW,IJIr4+25;pSN EhvsÊ% y:Q[a;"}tedU IDAT~J9B{^n|/T!o|0Q%o7=.jopt(KSU0Tk)[9u˭?sfQNR*&N^7͗$vxG!)ɥ46 ,hf}Go<7" ox5vyv8c.`F !C/(9Ea–HB$ $@B$ $@B~8>vmuw^L@B/! *xۏZd 94wsP}ldȐ 1)s"= DH^)"2%@B$ $@B$r4U8&hg/+ܱ`~!$䘠}К'4f1<ϔ 녈v\rmSTJ˚׊[vŷ{}PI!Cχ0G+Lv,U1#Cǂycs凞#ngybxo 8Hz!4BXx[xVcχE2bTUܡ8J0* <'V{ S$ebLεOK7E6~hnyC|d4d]e>H8_~nO a뿣\%+׸o'I $Y(=ݡ5OFj_'[uK/t֡O4׸ Bģ8.99LRs014us7<,i-3;!$ CO*6d]=[׌]$ٟٟ0Ni,*i*K')!0ƩB@bjC BrK ſ#EE7L{m;}cvǚ2B"!)D]㾩(+Y3!P(G8@֒WvBh>c~T !2!fCGbʊRϲȪ"_Aج5V2^Ga1H\xD1L3;r3KM{,\oƮvƶ(S"eڇ|ꜧRM'凞TƶP%j>IAƉKVݣ9DSK, `Q9"{UG>N^*GR9a\dd%hfyJ mL\ﭾ7QjZi!4})roy>3N ֍V߯q|kn.UdƉt6˜*kn}Թ+!#>^5!4\|Mcρ*\X>”K+"TLpw8fAe7et_Oj,y{0_z- ?SGdi^Bᒵ'ć?!4*P?1nU$>^TXB~CH(`,{Q!* ŽV,BH@HH@HdΙG9FZ=eY:M:QEDJyy0ɜB9o1}Q+|7cCw[̮5M:)XWa!9/ 9)cTސee`>/+5VzB_2u 货c`I>We'3?! nxd-9!!2{yʳ+uR@g"p^+a֒9GMU*oǵd/ڎ1u˿Vr` $]6pl4%c3Cd߂{iO)* fn9X2rd΂dΚdp7|ɜrU8ҰjLJ7Y)BқR8_Ua9s"L̙ !r 8V>VNQ羔3.5UdEҝR8_U^3pǚ9K5V;1sojfn,coZR BBXdcɜ/w0^,S-Ur w:Wy;#EK#u&h6RILLDS $yI[r9O\nnIңi\͉&M %I zB0p^9x2ˍ{9WM m3&ss z +Yyq,T9!pe3+/ !' $lfűP!( T ;݊ P ! `AH1 XqcEK<5_ (*1vWtBBN\\/Dr:7 !HJ8@]vK -]Pnmڥe W!H !W}q}ɲniFOJJa:y/!$1Jcn!\q\nf%޵0 "!F(EEExlw/T?1W<:Ba:ve֙ (u|RbDs,0|Unʙe|8KIDBPys;ЬٚY0/p4U+;fY*׎RX/""ѼYy•3*bys?WuE5n'x}nQx Hbaihw ڪgYGRw%B00%974 $3C рRX.V(ZnO T UlV]!Œ^]t$)^B"Ø` Q xb>Mf^mQX'J[Ҝn (q.<㭥Ta}dyfiޢ8b/Ý3[  cqv%,b-k}lDբnZ8Dmw٦f0 bHw;?&1j强O Hf K^ UDZ1{;%35u(yy&ݕM=dWkj&oXO`EŔd:`B(6N[.`"9sfeLў V @0(k-ϫG:[{G{^HH~}Hiu @$P1  @$F6Wu} HV ˚Z?#2|?/<;.DBB,5x=5B- SX1s$.^B!k)PnCD4QvU}X3HDds IԶ׾K\ Kjv#vܤj?l8nޫ:;2# KfbD!%/-$`C .D$SuGfUB")ʇBQex|d5:DBb͡<DB"Q]8l(KϬ3ш^m1YB)Wl4AZ-âW(c; =El9efDu|@w*6[2gPZh<&X%$j/̶)sr3m%+]59^.D+D$| OsԞ f𸹷=1%OQ~Vnqa~(UBK`D(A$H$>2<D )%@Dp,r(H0yJ6r~$ =/@$kA$ T۴gp9U3\vHf< x6WK^l}.H( #S9ŒUy|P}x?FrOc a@^$g'FSQvUUC/m4Y.\HZI<020%yM~چmD $ d1,Vv߱ v"  EQ{&Us!+}GTH)X%K*-X%D& @"F{") V Q1>JDsd #$uXD = }C{Lg ړ؆09),tFp]x#*EKwk _O7:\tIfmi7aco[) 3&Ma2uuzJUc8؍WRDBrtNLuum)^_xKyae}o6|NkQa}ی#xhlG.wy(S7Pc)3-kY燏WR0DBQNtz:6Dm Ƹ]yuB8;f|"B˯G7i]L0s+h x0!;XkZIPfw,BDVY;wDmw(ϙa)8TMnD΂T퇳N!1YOgLDkZj7P^e Q[==ĽXi'KsQ: Xs%FTe+!"qys 8J:Ec0v-]ޘ>MALgTj3igqG΁f< c '_>Oe0U=i|8J%Ho4DuT;Y5OrSMZ9I.0aU ~03()CTeku),N0: ͫ+u3 7| g,E׹KcCsiW7_|^T0fQȫ+:28 5Kԟ[O3&YS,FĘczEdZ r!cDlN$$z?xAHv5^" T1(?*`\2^3'Ѽ9D:Qrق=Yal+_gyuw B"˫-&4OA[DIś%jV\̦ "1J[ٽ=2OxۄTa~c8c2Gc,yM(M(֓>>e8Zav=El9efDu`X쪦Λ۫[>c}JQeM[2gA'ї;J[9ƭTO0୆ *!ሊSgJV(jD5bLs2DB>U6"Dj_xW[pAj;gՖʇΤiptk>C">mq?OBE'iZK+DmZwnyY'2I ! v5/G8 A7X%.Qٶ>UN߻h3O2SyDB=֜:=a v8J`}0B R$:LY}A$?EϐH{ y)! yX%_A$a7`\7^!;4&vzm^ݜV KB,Z&(5 9N0m/Y_W{cma^~ )JCc < ȃHH(rSdVN\NA4~n2oe~sfff[?WL6%p=0VRCL :XJ$sHH(DҝMj᳦x2*5MC}3V}"]{~DK@rgBm-SΒfK©:c`H_E8!;o.DMn}s+gn܅(UPv_89咠3&!_'\1DBźrO3UQ^U/XJ@""sYSu\ŷpRuX;_p|1y W[oܩn9}a7m^0v,3|p%5#P9bH+oP`lիoMR=/=VV~5 U#%J+7|F6\MHnʧ!TtsVSn2ŜoA$$*wvr]Kh,Sd?~Cj UyӚvYR8uJ{>X ,?^Ogg3BsfkŜiP@ #D"!aW|]4a[K!YXe~C5xDDgkeFUT+;pc~s5F8|/!`^kwu]$T Oo@UތaNֱRC|9F_?k ,:تŤsF\)DB(2>ˤoi뿐<= qQӷm8B[7,y5;UymcW8JD\R8YJC pgW5/{˟k >cm읒27Ls_8>ї;.*2y4Ǹ( :׋ X%R}ό,b9 'Dx#&A$Ȉ<@ 0"qp|qqsfH47k귥]ބEh 0D`0p IDAT7ZPUh п`qoy"_l֧d^Wl0 g]g}\>{Ĩj?v(mek%Zh?&]泫 Z ?(m?(_Y$F,^"*2Tccl"lVeVuUQr]aDlek܅7ezŝ;20/% HP Qpp3"4+sfTN+Eg?f!^T@Dyxܝ;*byںϔGBچ/ >Malop%"7߳^baZt7hڊ+6#W;+ i)Q!1J)p;X{H QσaHHJ"nbRʴ!"lI 0&BN)y -zڢ(AOP<, $A$$Qu(&,Z8F-jY(;zWͮ›cHP69*`Q"H(ZOZth뿼~KPl v~DDӌVXΫZ ip,* slA$$,yuj eѢ/73O\;>?D_WۄmI'``Ecgdy`B(>n%u̵H\쌚`"}~ H䵕EVUM{F{^HH~%gګ`F$8_ 2c 8σH  `P)%@?(:n|:_$+DeMm\qγ<^Pf[&?ڸ FDFDBBXkzj!9m~SX1s %\D@c PbvIPfDa:{=tzz"Ϊ'H5ͻuߡ|N.{r-[i]] mN!1Yr:ϑ>]FN…j i΢>M˶{ <#bVcWKeWooLgTj;5:4l\Wmu<Õ0H“>9~57GrH`-䦳i>ƢGu W>!hSnA30jD$KRtVvUY<@p,!H2eҷTM{]gGfD!xS$Q(#7,z(A8rYLbC=*!xK=<։BQdyIe<>2s]HH]:p; ( |.0/3μ;b4W[LhֿPE$PYҨi# - H51; =El9efDu|UrRdN[)*2X>Tf?oF355:h%^p*!W{YTdv|2P,Ccd}/*67֝I8o=AR%m@hQtyNny3̯k ed#w#v8$X=aV $yX%hg= Ғ& h|V y0LJ$d?D $e4HĻxD Hġ)e_{ہw_Y̞\x酆k$}( S&?_);ƚm$a$g̀xX4`n޼ī!$} 7WT㼾 TE2*gלncQ̪>Ɲ#9s@tlĹ2řL+>뮶ꍻs";vW%/srR. q@ʠkaBoOXuq̕O;}xbC0#gUv`4{9 EBDj|qZed⪟>Jcў J穔m`H @Bd@/#8GF=xIs )K#fV;uCR, HQv xl4uMFF$oSwʧ D\4j@2*͛E*JO/_sw" HnM{;[FQ>,,|(fڄ{LX}&>+}A@$!!HĽQ2gsZUna4QvVՎZ9vFip뷝(yYFtE9U˟^,Q9or >v -[0eKں|ǂ$_T-ظuM_hnzB-6Z.qKVS㵟idϋYJ;UklW4V윦ds&}G-qDBI`w{zm1ַDѣ!8BvÚ'Z't0"gT\Rz!t|4z&"P=G^9[" %#?#Y<1r=CMB+ -S)3{~j:go n +"S!<}{S)!bZD U@Ơy{ HPf;JW9jkDay&v1~2N5_b"F<0;ۄ\ϸګu[$b,pp9v(uEl_PUβL6%pIѝuw@1T ~`QLPdVN\nAR7X ф"!(Lv=ΰ<Z,\iڝvu3c̭3%Xo!1r0 Ɛtƺ)Bݸв"DdUOpys$jwοC|NAԍE *eB89Oɜ0V7@y<)0 ,u3O(6L#u[4]W-"e"z^f}axq2v~ߧ-0Oկ#b}NM5 s4qoa(Yf8j|*C̟Z*Ψ~ S"!BGSeQ"LS>4\ݢԺBX5:jEhy'aªnzIa>u7hu>wuXc!XG=H i9=DDBZ,oDL]b%EHH ɏxDDG"c[hs(Øa$Gn!uz gv2co]/oBXӎ!4YSHĨZsA@EWȋT7Q1nGΔ~CML:%V.Z$k:k:9T3Xl/,}-xjpk_ژ@ο % Mm8 FasJ߫1X%.Iն>UN߻h3O=j Faޟ0N7E00vB{^GE!C$q4C!lf D j{fg!C='@"dh! )  Ʌ  LHbΣ.T3ʶo}ݨ ! CQ)nWOk,q.d8:)(`Pzu^z2 ƌVL("CDBZ1b=oSNśM+X!9+g3s\ۉt}8@$D3Sዬu=ȵditDu8!xB]9sŜ-9$MUOB1h"g#h?%'lEhi֓\fnou|%UvϺdY} sVb΢j#B:]gŜYW[bJS3sUYkh( 0F G}݋hEOB̧ Z^B_:!"P"ˏ.,w1gWb ׻(C$D!cDO}X fu-3pu &PD:V0ƽ9^鯘3ucj<~G|:c4/w1gs8@ I-NhwGtk/C a*1>n sf(S/h5n8rq qH,-D} y!b0*(=bKA1sAe@b# V ++C!HnJHa-l:LGFRX""C` NB "@D  @$H "@D  @$H "@D  @$uc}$o(W:.nIɇ cdw;oOVXes[;)zb?5wރs-57w@0!CZMeO57)ۭ[OnU]avkw1:EĐ}g]s&OWMv֓[Zg]sJges^ox:n'O[1c9~[]]}$I˿k\7"fv屚N;(摛yl?n}冢ko?uCçI8RG|(L-ᶜ7wi7N+wރ.k﹝LmO7Z-̈́ft}!]>eH Q"^8T7lnw<:w]2Fbڽ.+D޹XP*O7tt?])Z"[{M'+:fB9U?_BQwTU9q9s^mY^7g[Y0I)S[;J<]KzuDO|_ٲw,&1SaĶ ^ef0Bљ*CDMܸn/w\_yk{ !nts=[>W1-‰K7y{ B7O\fwꑜ,9#{k_DIc(y|SuW~Eg/,!~ѳzMƏxz{}{!#PZ={‰K +YZ !b=gxhvZvU=MG~L˷8W4!di82f \ܷGm}峗hl~"~!\{`kzD>?ƸV־r NQY BCtWgL+vrB_|rtL|$Iv.B߶>}$|pvkF\t򯪷}u Bٵ_]N _vB5DI!H.0Gѩ|vC#]ڟ}_Uo39:Fa ( !dr:&SC7TsJeh2]=LQYZÂE[On|lcvzUhZ?.3B;Q4*yG~{M&15L1croz;o fm=p*7='xCtֱT'Z̍eOluMS iߜ}YoBcvu Z--6w{BzMIDAT7to7^1 m?F!fhrt^h9ϾSovb?>7c5}rB VP̖q3PE%W=p#zuaISr m @T  K/7>+cd=;C4!Dzp WI!D"҆.C9|AMs@lnWҘgrt]NS%b4 mm !Dyi|I-c c}N3 >l<*Kk>vfdQuۿ}w?8g7Gqpkb 3LM(ΐuڽ5:;L[ü,azIHNZUK˲ $1[=>BJD 2;zUmֆκnX8|FahF*XZ톒3r#c)V*ݻ\׎m/''a ņ:nwA\9x^'>u{\u-/f6+mnڽ+2ٍ-+VXvb!&z i9j=>Oy~U9[> 3Z!P]ウjM rJB$Y[9{Ϲ~Х}s?Qw{9/M148\֨5 Xbi "¹W{yѐcvvc(ɺWWҦ Hzlϥ0?-n|}swˣ0"tڍ/lz !Daj;Sjb{$!n(r1L6dJ QjI`i٭SourCZNӴ̗Nm<9MC|> 'MYErVnu޺ pY?Zxݶ:uAFQ^K?\CS‰qW~Fm]㓣yBn{}dO)[[p3͑ HDjf˯LхKf/9ճFͿ0?eFC1cK_>`u[4: i㏷ tݯ,ə@8`1L IENDB`dtkcore-5.7.12/docs/src/dconfig_example1.png000066400000000000000000001656071476226660600207310ustar00rootroot00000000000000PNG  IHDRWf$ pHYs+ IDATx}yeEq~   0 wԸ%1F$&y&M|&I0Q/ð̾GwuW{\7{Nwu-ߪs. Ƽ X>Cf0q8W89 q:M<9*#, n}Q&MA 7#"5ǧ9+gVR y"jIxHؖ\(#HW K>e u♌)\G9LΤr@׻(,I3eb3!fX(ҥ5@N59j .pCNdH*p9Z uUy#a0BGx7,_ZO63k5I,&NeXK3MLD-X̅ )JMwȗbˎ UaN: w@C.:wA?0`2hN% "h WN&!pRT'RvaYA@kBPpq`׈ƄF&U ڪ9T #]|@}Ӥ+8Zʔ86qg "]qHG^qHgG*P*Xh[0qމ78x±/`H8ռ凑9puWW Q7NC/|Ē(*Et9?pHwb>co(R H{5{eijdV媡Ew}]0cYWa84=82/1&h}*ev3D!b`0QJ"Zg1^a}PABaTQS8!!W@CQࣞ,lK1}by"U jwGG%ҠWqX+yPpG[ǸzjL污Y8sLuC 3"۷?,[0uuk (r 4/`.%fp[(ڰdeFst QNجN2('] :@OP%ea;y(etX&Qe$.yYb!3ratjY֬ӢUh%YPZ)n6̖[hN``al!L!‘ns3  A`+ "3{YnD!K h4A%.ŐQQ;FY);`m55 ˆ (`, V>*r9'br9؆ُ̋?\uXOL;u @0U\%wqРXK~O)RMgn0?| ;;]ko[OJM\9phZcArdm헱5?[O7gL^:Eq1؎([S@-% |>(ڬԆ4Wg Y"|BDK1~DTՈ5F^!oR II|-GA$W,Y3]vV,o&3abaA7!Z[`i@%!O%?1!x`q8VGvr Ս҆27m#G}",XbPJ:LqXt\p[TJ]iG#Tvs~(g&&QM\~K(~l1"7< 3:1CF!Et 3ے`b[`ji9D vRF$z{@F}$٠ LI{8:*b I,@;8mURiS&ac0sWh S<=I,w ÿbWͭmhvkgڣ`IUÐu.Mv\qKb7>% aԐ=|tf㏎{|b|ؐ"|[=LqJn,[R>͂RH(;|Zgz{B ˯$-X1&uvj^@Dʄ؎U*8b>1*'ӀMcLjaX%YJd-R vN* SCs_@m[R?BH.'&u[X=!rDd c) 2zi&-,v jf%5,i3/(.dԚ;QDXJL'H[^kgo[_˺:e=I&#X<Nl$lDnq{ 88PB‚ b+Q1Ðe6.|&Ɍ͚Z*" -C0SbKܱ2 o >]R.R"er XsAX2Do[>{ftiEBfIPHd| OI,$F\Xҟ?AVg~ӭCYF|EUzu}nʅIՔ}&W;N$`􄒨4v|m,FF@<E,+;|9ˡxfc=,$0V,#JC P)R2K$h~1WAIљCöS& Ng X䇎&y9aYM'-14h̓G9}.AdLg'DF6|8{ YK%תq ˧mƑЫ]臧@k`_#k!/+~Jz9{=\:~t969ذX:\s@ ?]+x,t:ftE`,Nf/|Sx&c|B8Xx* (8K1zVRc;-Cܒ:O8qE+ "qz/F'pA5ξF`fj.JGd#hf5X[/gڙTYI&Gq'T/#EN(dXzش;{5 >oPf8Mkѷͧbb_B M&ssoe.!82ЙOa6ܲqy= u\K:YKol f韟Oߌ[O\QذvUpSty,ʘs w=l8SⱣGrANW+q|6thd ǧAVE m[sm'cqϱk3ZhaS|Nttq|#z&rg>AS䑑سm~v*]wƊyz|v Uu}N#!  ǣRrmNtTH ob0XG: q*4!Bx租X22zҤܪF&t0 qXBI@(iH 2Tr;ȦgâhsSqA^"eG`!Tkə 20C*[بU9Qq~톐]8*>Vk*qP]WŒE9f\&a?4.dm#K"41)NѭO+YA--L:sj/&-Z"33}/Ba&rDG|#g/4 ` @Y&&QIULEK:'LfdxaT(ƅb`U#AV -6JU[LB΄@Lttձ>w1'-J@[ &;ظ?݈~Xԥv'?;'Fמ ;gZhNߊOt=Jn@Wud Z>u;5 t2̵NLka݀%aDnG&o?U6|}~"1hO<[tK̍g+2`>Qsf^o ~GGڃ Ku[x2cpp9~'Wѣ${iI6' `\?9/9M %ý%F/PHSEGvT5L0ra+U}B4|ewܾ\Afp-ˀ@` ͒]ME{)\)F,_Z_MmA04Ó:ِ7M`;䢃|r` " D8 @;|.TH_UAYf`Uj08Ď=Xa.ޟ)Wr,q:Rī<´B:V@|^i@pe=}&v 7l=⅋:﨩3O{ཻL-RzoS=lü(9d{Ŗ9-) #fybWÖ^ZF.CT"R+e{\/ogw __N?>z}R rest]?Y j1 L閍|&{mƧ1iu&obf"V$Gd8RԷBƈF2nq[pݹ1}';B3狖)!o~ ʑHm,C?=` 8qRl#&BNJn`W"z,iasACC::\LL<+`S\XKw`%ؽln5 qVY eю(3kg@!igy`_Nقi,z"(D*t CaA(P1SVB cWj2<`LELTiO#g, %C=%lFƻ@ MS+طwИXh G8."G :(K0Q҂IM1Q . !=Caw&6$QXMNq*z_b4WmnDF+{sHfA9 .DHp(c:GR>,WϊQ{ګ(x"&TT o}Y˵m b9<1dJ${F6)fj͛Pca["w HkX[+$d6)B:zbnH9\Ѕ$0<(FcLcw6 qal˥Vʇ`4;+gik*W%#11R'|2?& yOBOȰ.VeS.)*9&-*wS{1 iab*#R=3`L?X ,GEwu ZhK?( xlHUѬOhe;b 6c[2#!İ~:@3P9ZRQ`h֝^/Jb-TL{8o dC[~Tx܁M vhG!`97&+eMM  p Eb "u&Pkr`8G%^w*./lr\+r135{Y$! s &9R>S86 7d"Hn@P:cVه,>%N0HF[5o]c{+)'Nrk \4qIz72;VXG0F[|"8,@;:fl:7@cZ\AyNvB=-[^7}}Ű,C&52\rѣa]/ IDATYF =!{]y&r0qZJqSu%*jHw(|W Dj(#2u,&$hc|`cM>&8 ReE$@ᤡQCG4dsk۽S-YzjїޜvE gG貎ٰeeQ|ذ `r|x}t`@Sqݴl[e~v2Yȸ"1H]L%{ph>ڷo<u%<"twN .z88t_x'??@8v?.ڿӓtÙ;;No[Oy(%+X>r}[gneZ)o܁Z.~_BS~=P8f+zPCHQ91,28 !LawNz %pf*L:7ƭUU$xʢ*VzJZIҥ=OX1eY|kOfKm)؂|Fwk] $ƲLjE}*f1\_xa/[a:rBd}2:`a6} l2m<+hT4*b~LYe,55\J6 [xZI,'A593hfScʌ-iҰz= {%3JYZ}H1 jɂd} j0}=:G:Ub F2b$#gZAKBPEhPTI@:HNYL|OX!Ry%!^Ȕfh62{JL G,B$n$#H `$-W#t6N63@Q2J0nB N/E7Bߩ+1R0l"11K[a/[Zaǃ}/hHH%J E ,U+Q _R9gP1P}F Q ȘAA6-LeՇ+W JRŽ ڍ,739l2J)HEc0irv(JMqmiAfԍ C Drld8%(huPXvd5 3C-Ane T& `MdQ9tPnKLC!Z˰e;G} K6-VV( _PI1Q=q* lT?e&UCč[m$(*tde3Sf9ZF_bd pCf|M4&ׁ 173 3 f | 6[A5gAuGT=Sq)%xH4քbW5I< A&o,xSPJPR D<>GLRqb)1 Zџp (_pO1P?*Uņ1B3`xPBV&_A%f?A}hBS}yf2[tn6K'&32BvXG/JrdrΖpҔ.-`` q&8'"߄=`aFeT'_6(EJ^7(S~Xc)|k2P#7& 5 ƕ6MYcLX|775 9à,[vxP@F1dm@qϡ7>fmA" fd= $vkP5ϧH$R' .O㕲N2cL=$"%FIq7!e s0kv#)̊ahT?*"w8+v<$G{$ @X&'j,U!M%d-l4zOG ( : 2EXU p4`lMM䓓YlԗE.Թ :欉M kآP1@9җK 8'"l%"u JbT,m¤B!%ffd~5I[[CeX릹e5"=9O\Rȸ6VT&[05e.\z(Kw0`CXF0$6^RmbR%!("{y$MT8"l ZG*;aVH#9/kR_ ~X*fd()!`S9G-Z ,)Fy1*1X24=ՠ2/WC#93Baj ӅÊsWK~2(^ɤQ+H?B*@M$X|5?%/aa _Lt>k %K,{XdKfd20\w5tt%[PD5'ⰈbXeb&983>At,mFk,CbTbsHA>&$Aa Q&&bS+ Jc,eV#c :jTSV ы lzq%A&2Ct{0PJޖ[y[DSϤ$Y%?yDOܼ!zY}0[RӉE%IHE\ GB0bP1"LXUs㠓ZAm+ ظ}"/R3rԂ T QW!+C嫜 KaHq4 JBi &bbm)" C1PraBa"[-%H<ŠL᾵#gF¼ %%"+3aX HdCL 3BE!Ώ <rΌP6+K~h D &,S!Mψr a˟.J#nђe ޳b %ZwvG?7FmE E6C>$*u>doNjn\k5h"hgylʹyo•auݭ`#T>1\q^'f˶$.Q\=-Ki 9\:B?XtEÑHV, Ҿ$_5j!Jz>2KT( ujPu`?BVD: 0hBTudM09܃I}tRo "|8h'G^Ҵ_w(S0!!1L7ÔwDOqx\Pr+ 6! #LB!d^OJWh &5p̋@qӜ[y""\TPBRn|4<2? ʪ^"=9Et0G ?A@h%;~=yR=~PX>r2񓃁e>+DI7NjJ㵧p4.;XFߌ + (NBF*AM!S~sa"Qm*C{H+YA`.IXQ̖%"\24٢Ѧ,߿Zy,g&/e?y`&%E9DY-,K*-K>A0`C Hb8$SݍONVm l,qI3d9euse09c|k`Tȷ;pAg?(4L4^#Zu7`b }?ѻs ypS. `K| ׃qtggHY4T!Qք`0@o /BV ;ZXC(,>!lk@d}1 J CU[߬- rUY< <%ϫkB&$*6ɜq%j3zg\?b6,F=ݫ$}$?'#EhiڑN; GYtF8w-$ċS3 #D6w'RJ$q@0DdiP{å;1C0>P2l6QuLHd)#"O5UlPKh:zl',u^ r%6X,:\\氆АLs, x U 2 PfB1A-V֞~ÄTIH+Ys$QE /lN-=_2֐a /[/ o31 "_$R =[ ^短87})n*H=҃]PB_w'Poր -y0`Ƚ!\UA!&ʷ{e"dn/8hzldng,<<}ן2KU#bYWËtHJ(<SVPȃ v 2 ?-|ȋGD':}o?ۍ3k5?h*좇/upB]@L͚{V\x.6pӶsܽ4`Lm>~w8ӫíOŵ?XL2~vї.|~湻&9nx/_=8%l|n\Ahq2;gWeŒ j>n9j܉kNfqJsdd]ZZd@z!`*@C%YN m'Bref Cš^3z66y΄d=C(C#_tQB/T6#  ȥ ]Thޙt%>oaO/6Ď鑌\Zx 'J惛 `j^4cX7C2E?3KsV>ƍN*EO?"Z"3l:&/BRZyU>=6ťL6c(DB#8D R!8ܣ?u \85_q$OY*~ ʍ1d٧om'{uZ975MYO}=g{1|h;]u?W=/_zË[ȷ W9<ӎw׳NqnMџӶ]t9xkWM73NwaϢVm~l͓{9ܾG3") +1ȣr~ڨd͓UšԵ4u#g%i̓l +miKߪpI#Q 21I20U )GH8f@4NIC#$1 .JZ(PϩZm)qR^H KuCgp=+bH!~ٵ*_ #Ƅev,wTeV0|,x&,SM a2Ckjl2*- J/,)Fs$ ,O2qv 3Jj%zD cߛ&#RׅԈ9%[S1z yH}+~d#lw a)D#|ox:GUi?qk˚ Oݱozrׁ 1׭?=%@^~ǣG17<ދOgܳe폮=ᨩ/WK6l9;ؚai@uʎϽJWJasZ~ֽwO_~߷Uo MW.K6  hW놅{ xo׼Ev{[W~" f|yfƦu_7UzeoZxx-k.8uEL^xN'.t{;;7ȃJ{w_ozb$tTуϼU!F8|T|YIʀ@1cu  Y( :P@:'#B ԐHݿS{Yzz$CGw3#|YglU߼#9|!5`mL *ӝbLNVh g*2˗ܷR$bDtp V 3 +$/]yw[Hˆe,^(2} O nQBRV,ICk\0T(0dTZ <%C!A -BBMHG`+xNRbg [Lԇ_k2CK]Kw/>Y%h*IBCdֺ#Du@ DNhEKr_[f.IQH/\i ~q/qQٷH _5]O^1,ME۷mf%o 5x9_`G3t IDAT[HOm}1_N]W+oai.i?p=4?v.Sҥ;[O/jFa?_T1xdNJw|yi {֭/+~,!0ؓ=i݁vczEsNخ7ne<pٻ#p/]'웞_3wמUgmؽ?zQXs'm', n{;ywwk~rM]{='_lٹ~DVAp(K:JG2֮Ñs7w=Ŝo?cş]}2l@  3dz9}|<w8G\n>K7m:@%п]ѯg ߝh ^\^95$?? ӖkŖ+O;~r2?k`-}/OaƇYod{|_+ͷE x佳BJB(!2g0HY_rfl ʟ}<|kۘ5:FhNXFާF8]@$=GH0fLϵͅ^cn1=ߐ\5W % H+|kw3Mf :5hH ٲW?'>0@5]ZG$'\)i\g۳cacۘ4 ʈ=IO*Q2ڝ~saИ6f݀JFdq?gW5*#E<_=}h)csd5ݷM7:\9,PZ*- ׆/PX7bE{&c^Z,~cۘ45Bv.EO@AG,j!ƀMIy bYn\ LwZsB>kt1<~v3݆UJ% ܇ȃ<| ǡbİ]3}I_OuBryF&]D8g\oQszO|/}m {ʮz͆ ޶m+˷+W(P|;kW_ `;@/ݵe'~nY7^~~;s[?}Wy߶v;_q;_qkY/,Jze%'/>ZoqĒudoD'=? '-q۾/왚.syC[.?*ƽU8wz.qQF0q5o}:8o΍Yh|G>uyi^_p}܅l߾{[rB|ΙO[gNR8"p V1q@眴kC%}ʡl/Bsjy^ OۺbQwėn:=ӯOWKx ?~;&[\}W~w_y^ӋNۺx_{n_;mޫ~7[Em~_|h5۩ 3iNͷ{7wfV߄kva6iMͷ@|]o{-l6>gG|ɍw#?`SuOO|Ǜ?;Z1{CdC>˶ɿ ߲kB` ,j>o,t/F}o%+g;w_÷gyf>sXmc<4huA>МkgbRu:7kxY{usFߘNsts2]z|Տ';޵9nN믾ӫr/X298;\՛_Ko]so_:bf`u[ mIiac4eL=m l> n{~KgW=$|ݥ?[z|.['oʇ;[g}5ܫ~̝O䟾;~tsl'OiXAl>|w9 ZsƠf{3v7}r ONzlYk/6lDﳿ?7<^?ڳt`~⢓|Y_߆OvDӟ,K;O7m0sKN쭗޽qN+w?g[lz/=i+Oo\rd3?=FfzN jm̸_yCZݻm;]FS%bAWNSgp 7"jU}htB(ꤘ6%!gA΢ܳ_ ybY2cw뭥|o?8&C}/n/pTK&G81@<{M[dWy-Ѭ0/TnEvYO4^|'pg8/ !쾗]lh%ajN^+ٚc+oq.ʽδj8-fyoz pY4>|CǤ(Dn [o}q=J?UK?gZKZ9fe'YhV~ᨩv\ .z'7}1f׿ת9XyGG1eip歏^ȎҰ0oȋ@bDAg>ĮeO^&nݻxy#ڻLJXsj~Z绍7g;(f^; IwYBIsN  M0m06Ɉ@T Es:Im~tΣ;]]{ /=);~犧oCq鈆oyڌpŻ~"Θ%{tn_Ҟޜ bʓv̓8VhaVfcpr.R^\P w*9|H{Wwׯljҧp]!+qG?;%gTOߺ=?s'yњ><.想zc#C+r{W=_q93wugn9y@/߸#8g+kz_ )K ;x`ƧY5;a8EhסC5=C:*a,U,IURr 7/ ap6/;ypc te_K뫊սtr>s:#_,Ǻl>Y-z ꆂHf)n(B(B?kO@.>?ы)n(l VJ>pɢ~t]]s>"^4~V~;*l~9\px鮣=s FN0G?T\U[@uRAV2t\l9[JtJۅ\&ک`t0+3wՔn*n4t癫}]#ۿ OksLgQh%}\d^i4"7,{e+6so~Uod$t aU+Oy.9p7E?Y<krvWz盉5_q6/?+v#V쌅H?l7?tq*ζ L ۰i/7d;ʁydȑ-{zh>J朥pq1x2w y)"'Cq7?jTߚ=r4Td૕#~sUuyyYëf-mVXޟ7NDd%f:.*+-\GYjg?` "\|h"o=U1֜ϖyqF?mwܵØԵ. #L~d;!ɹs* ꌳ~sblx˩;_ztDFSגvfkќ?qWN+΁+JhJ!D;?\8Ahdra s7^ %&{0ef:- 8`Naþv dǚ fׅ?o;\H@߸\qv}(f-F܍= :ۢGwh"8ޚq_״@,{/;`c~աUUc%S V]6u`KR$T벘U/%ZC_OMdԣJp(ǺfUUPX^9.:n!+4>̇~$@ 84v`;}[_8Q<zKU,X;{Z.`zK#ә^9Gi.ώ$` 2Z>ѓ- #XBG@pԝ/7pϢ7}*j4lҮ\pWeQNLZ>N?ޔ+w+eyh(2h^|de#ֈ;u~Gvf"&X I7pӴ-\O!G=pŚ.*a]p~N1]}bsN>r˶V!=Ykxp3d=}ѫC+/Ys){K #Y;X!1™=)'u|0>ha}rc˶U Z]+-`RJg,e2Ы^HEy]?dJCU 7O9@'=0ry zP ߮iauWڛy M#/#83ʺvIZ ġ|pv$M0`( rr:ʟ]pf oP @ѼP+-k+bĐY" LHpƹ9ɂ.dPHC (._}сڲ@С] [n=o~SwŒx k*bЄA^wJHflվQOG0r$ w^MǜzQQ7dHA ǓND? W%x4m /+`k41dL;Eo0J:C֧wFSYW2״{(]i/d$[c|򆔊Tzd)뉴\t7bL =mFd@XY:4O >3 655aP&?t Z oW{mhů#S<OW8\P#g0(yX-CWOݑr3|ci>1isxHbaawax*wp˅ (*ǿ)okv#󧿰'1}?5lkŇO2 YK>C}KY0#: R<cZ ,Z8pՔK]&籙7;g2s@&h y&9Y 6 T0wZ>|ʘ#-PR49ALr <ЈY@щ(n^ԷqplH ̐wUc [5 FXV 17ä=e!mcLKiT1@6yz \uuh<+({$P͑Ai<#d9`$ ~(>}_UĜ^;49Qb ܣ5 `0npG[(7p^x\QAnu)%SGYugYۿa$pU{<#hjMvd/=;2z̀-1<pF(%NPA$T\L $P (L0% D$ .4dYG 9v=lB'C.sR.Hv, )0ͦF9T05%PUTxPtrn P&.G*/~+$#uE<_zъ]fkG?w  Qs# XVm][<뢍 IDATь8?;B!7;3YUg}奭 !%x#uyT~#dFY̤B]rzݰ<CM PYAW]k'E:%<~熳yцD%{^sŹ]fr:Mn=TBCj|oo>럏|}[̏uf^9M:K :>[2'SWm?Tz#]}ԘsxOguMTA-`W"ؖݧ^H/U0w2b`Ckq\GT-\ '3CnFtC"a73䆃nvY:ᜭ8dKzluѶC^)*JHRuUf.8 QY0v5gnm?wJ[gf-{zƶ_/cp[& Z*$CLDvӚ<4m{i qz.:PqW^v,`ɌOAX)Sw#vsӢ5-9s>Z5K2fm&aJ:?];* Ya7Uđ\*Gy)lmꊇ!&Q %'t@OMhR1IK%hdjqJvXHVk P}1Hk{*O IgKGD=#%k' ?FA~9U2 -tC=KTȱiFanWM{{mٙU*(75X>[sZTȎb/CnAdYqɌ`a9xfE,ds!o͞lSݘu+.?}ϳp~8{=ߜo07ZQֲia1sң-~d/lȼ?d-":^ɢ1L*Ʉ|r[~#7gzC$jp"!QW,h~d,R ;vF/~:ۗ,:",႓Z'?׳w߬Ͽk5=:cLjoV o\:xKIZLl-Zϱ6wkΆz=忺rGO~Wл+z鳳~w/r[ڬ@TK|ctAg=h޸G~ד7.~ykcU?qS7r& _䡫~8Xp.!XϟL{3y oV|, WF-m.΋n7dFcK:G .^ձC#LG2nB@3yƅ {SGe>P^ &߭1WC,<^E|@|} k͡mc |`4AAst}=Y8o:s_Жyn=c%"i,r$=gQ/OmU.-xzԡn<}ڎx&U\,.n.p/iEEW{ZUy3,"pEbl늿?]/g'=gցo,8eCGsA?uHO|<^7c|nDkWg tc}[eaN 'VVбr!>*4M_u/ {xT`Á>W0y@h_yc^ "HjX Uw9r%R6@LK@"L_9Qű\3nƚ$C+w  H}%uy;sTDmkΥ< h`Hvxhu?AI~ǫp-ZtU 7 H͟tijίurm}oXW}gz߻|rln#WgLbȖLՎå>׬lTLH?}hj\Qk:cq'h"'?c}ez~|w|.EWs.3v*Q2gf“o 0Q|!8cᦎeRRB+BAodڹkԵFR FRPe1{fbwz ˆJ7vgr:!'=`FTnh}k PcI=4O(0Geބ@EiMBRCQޟHW)F>6\T=Tұ;_#e~Q I䔤I!#pڠ]Y[zɞ$%!@H!Đqұۆ7vIqUlp:EΘ\@6gTіZ-:gV/V(r=tPLD%#6۴d@cw״e R\4|O_ަKs7B'PRGOS!*rV}TQlĴۜ<^)[5b ]ɨq LDX({s|ǧ)}6)8%T{)r KztBZ]iKΉPpMfY qmLI 59)=3˖v0Pmbkwq>guJe>BGVE}ѦeVz &WQgCJI@f&n|]8suCz 3B e:|X |852ڋ4n馣֮I3X6 =rKRew1⧼8C5#(i'@D{tϸ@PM r7ďR i|2֮ͥ8R3f$oD&!E#`^k&|49B' 6P;"›)fʩJM"Lɤ4&'4aZd$Һ&i.Jºi1}^n_|__00qWwbf|x#Mc$(%[xt# XEpr@;TʽzM6(̍Էth,2FNOlR &Ԅխ^T5* c<樂^&jm 9$B$WxʥP#EV[TGGIm]ZĴhVUSFX2Fُ¥ݭު3fφKJkfB5r>zϊr)yEʏkEd7B+v[j+չoӴ|t8'+䧗2l*h 4P`e1`bBr%MH 0\q\9*E-7*pPeuFwT1MJ``.p ]b$Q$Ja~VW\?N F kYE{Hnڙ_L k"G&::\'nL ޑK 4>Zzүt޴ddApJ0l9Zz_o3D-` d֛JaM[vHFŚUv-OefdDU5Th. nIF XJ >".o7eݿB1=iMm` R=$]fXk4F&XgWJxɇHpbNjc6+M_@;J*=R@|MC0EAM0ixV*4gB5 A4Giʇ1TEj'Xp~JcwKy~TcSb\*PK_c^((OR xV":YԾfT7AqKL C%3)57N #p<~.PU}&%xf<aSSk_AY%1|ݴ7AF$U82d)%WveңPP- ']93< ّp4+(5r;Fڐ˕ *Ts \FB%wZ;'@̔#j'BMDgg%RP% y+L;ꉐ߇  fo`RJ穏L@J|C7AK r枆=" MվJ &s>-TTʳԸzZ&;YҐ lÑи8_D*D=}Pk/ Đ< TJ~A!T"g2/I#xmHU𰉜 cHJI[8JLeQAo0* mLGԱvǔsLUiohj W&S\h  uhnV IDATVaRÂr+d2^XTVpRdLTg$M#r&Ra+pJ[2p2 (ο"TKGR$ L \ k`IH~!0y|#$P4,"0mH6s@@B*q+)=|VSDm0ytߩjIq)jpKP APK3*C8T&’S11Ȁ 5 p(e9 M!ڷ1=N"[# @*eL|Oi :0RH4I9C@>zU 8ԽI b= cL{" w'IV(e3~ S["5+_s#=1ϖt#%yH@~ܧ8*gdZ͞ ɣ@"&؝QLhFR%~Du#_:LMJ7 씊ǔ`$0WdiC DI r Y)Cs0DCRZ{= nYs )5S  B0eWN\6ՉAdS* #i2 qQq,eVJ2G"xeH$e;"&E!DLxX-"Hj4d )Ea^ >"D$ yJŰZ Cʱd? vFsJQm&Ȥ\ʄ+r[X-Mkd$:,Ã""4b@z%7![$E =^3Z#+q,ʋ4t:҂TQg:5~/YBW0'J7'D jhssZ>!tό PVFr򈪣y]qYw}zuDWT !ǽ >Mh}7Ɠʌ\1S_ %IIUHYޫ\C*s$~:_eS&rt2hU 2*Ӷc4d?ll3)㦺5R PG8(mlCpH(%>4`VzFT"X4D~\nhj(D5p4 S$p#"MD$C}`8AA/b=u#(ض2 z1ag\3AO2*yDb1\ \\K㥖J]voYH+>RQ+bgnQ)g?Z! =Sݡy ÛjF8Cߚ`:9"2#GSHQlVxS[4&ōȒD-uaweAA~'5+6M us~NanfS{Dh!ZJ 'I0qw~N`q% JUчzvF>ey=H~yoT'5Ӵa_3FV54L}=?8hv-sl:R/~@C&~- B+@^0}2n9$ZGm? hХ&=qTEW^T|NsWF0@ڗQ+\~tppP n4J KsgP`(oT11uSZ  G#GX!dQ#<;*]H$e!ߔJQq5^˽3LSL]9kpSOWfU<7gOg'Bm?\ D]nWAd׏,eA}MOۧu|7S~2}H2 bHe``SgO}`bO_|ѩ(m@_af1P`mՏNP:m ) R_8ǀic`q [ 8bF vy iq #`Xz1Mc11 Ё+1C)c46 %-d[OP܆&LoVRu'i+0;1!<4d,_wvYM <HCY)0ݪ'dwY' t4ٳ#јcXJI PzPsET3].7h$#qx:wاK8uܮ֜V`]`Vf,ګoiQU>3p D=G;as?3~tB /(-KZ:2aCW cga}3__0o̞'S sˁҬp⎭ʾ]9(/;sOdPe>=~;_ߴSՌPp}Ы{v)4d:8mXu(3#G Wm ܬCWώ/|[;#ȊݺLBszyO{ڷ% ix!}[;PӘw7TU)x7MvvCg)&@.K ڑ岑o>3o>jRH^}MU'N-&Sd"~R1~RXǢ;\m"t8(W),WT.~j}@%W:&,J PKFfVDQ:X;V'$`VE8vUY>9xLu-AAAJ$76O!$u_\5A7DrP]64ʽH 0bӥ xIrdX H'!ЍT Sf2B(D3PiJ-;10[Hn]YcCX4I噘 JOC[(Hpϧ}qCzzk[:T[]/Xx?5{xűǮdi }^I^G{UuԶK+~n;?w9>.mi$Oyz78?\UVGhˆ`G4D ]}G޾`_MaUX^V#8pθCYYˇœ8c*nkv^^=ޔ3fq9kwu\cKTwqL ydcR!"]w3FT<=ڕ{팅$k&]I8AV-W/ :|Y]kac{vB+}Sꚳ }-~X\`/q?t7g`À lnW6c E!X*|gq,fwzg͟4qZŮ4ُqOsHPi ߿2j[gz7Ƒ0,eoJDIJBePT)X eKii֍Qҳ &5I*}d[ٰLFZ(נ;;ˍ`yQnrrha%/`I(@ oMW%`NAy1$qL(H𻮦C[DE@HLk&5MkEj(NR&&v2qar!)j4h Ѽ/QBu$J%H7`h/jh}=d-6Z1bw^Qd+w!/Qۜ]O&ȉ$ZG}6oԷ^~ooYxˋ'o;T"QHtD3Q<i=[^u66][^% K P1o\|#Mxà[:2wh҃̈́!7.弻+uiw^W.^<oIXh9Qލ_y;k@9KT= E+cN]K5wd̩m9֘׷fO_<^yy[pqc$ƼyhyYџ,>1mySf?XӘ+2Xў7}O E`Dy? |m }B''UGѤ H́ 'Ȁ AEe3 U6-jnV(Pܮ/Xyy%o&apA%!Ύ&\oxbMӶeG]VDAB4OmoD,o0A7!SA (dܺ7.~c3UvJTqYѧ%3Oxnyj ~򈀑Ϛ~2ºl],,b-(ٺn*nJߘ4_>T#9 N(ш+Z4zE'zUQu$)xlsmL̯B1*`a0XfB8G2'!/-VEÚ+Y 4:W7/Htgʒ3 "LaK`B.ÙPD"יdW麮Bi*oxb}e*Z@tHޱYEF'$wqht˞ٌU΀@2;AK -~P&A ([ ӯ:k= -O:ȩn,SҔ2ܬuucN(*nΓ3B@* --n9uy!}xdӍۭpFɩBoXǯ_x 'Q5DUڑO#'ޝڌ.w]m=MmƜ5MUGj\%(Qe,M$5)TK2z*Zz"uI;XV-9Av`AQmMMRXX/_?D`L40;"~;A!U(ZRѵcBHn$2L9b4ttL gxhW_dr>iT߼R9q>5'c <;ޯ}$kYB 1!{Ҙid|ִ41l/30Jb(?GWVHS6XKA&aȷ *rj QLbD^*Al ZRT5UK/4k:0xCʈ%܂na/9mrbG4▎hcPS[dW0i#+HP @$(Dьy0eԑ]Ϝvzd~yٱP3a/Jg,|13ѧ-33Ur9uhgm㢱_~nt=X;wӑX=+y70':sPqB>8z3rT8t5g&=GȐ,#m+bw{_( ĔutM !5F?fWs1y^(,= #8OzFSdemh“wmWM&a卥UJz4x|>v .(0,97pҍ- !%T&$^8hva 3Vؾ+S"?]\/]d;[LORYv IDAT-S`3SZϛ&i}*br.Qkt .V%FMyjrIHkGhO+'0ֶ g#Ez!HZ+&f)ZdCZHIfzQh ~}(RdON| L}#؀!Ӭd%_iFFuCm %,Ő1@R`f4-H F]o;exj6][}_{۲o~ݪA0o݀ C=sշF9?x0xč+~eUC-|wU1tB~pS-f.ػ%]O?[\ՐwIgD֮,KZpҴq#I2C*<> , K])Rl0 QKD&116,(Fc]TA4Ez[e;۟}y9g̽K|G[=gʽUӾ+ѫlxa{M{ (eo6oY6P`Ǽ^ի7+ViOᵏ^o,b !arg'%;#ضÕqwa"-u)^޶<c~kКj p۾-B;ɫ]tK2&(@k?(ZbNӖUdn+4/ 7C}>l.+-H ,\ y#m ͅ~7^bH(@Jz!9UqȢcI`:bi1Y!Qژmp[/&\$IC=AJx+pee]{ 7!zPYn @(!j̱GPcN 'Kb5iY\p= ۦ+h`9n(r#g Ffiɝ#BT(X"9)^'J^GX뉔Шzzm.SZ+\޴&SnBy"WX=ʭ̅h ɰg|ԕ?uxSA SnOEo:5Yj3]%Ko1G:@=G/Z^{~5PWv[.dIǼ-=\|+~:D+ Գ|9{9Gfן8Z9?`s "ͫC #:d44#Naâ509{3nKk2gYRΜġwWzsB2Kݲ_ tE߷Tڴ -Cu̕?2oβޚXRZA6Ve>؜Vm=[tC,M&c1|1ztܐ`i{B޷`yv\]H `͚ԁ?NqWv-oϿ s"=f=ԏAǒS2~xh\7i4DIh2f#!O^J}v&i44Yiǜ+4-=$#c0 G?唶r[;!\(k+4Rx'{bt]ڮȪ0- g ♋I4[.AQsR8W^&RTƙ4ؼ!@K*"!#Rk9a`;5,fO^Ӷ3fg,GbbÐچVE?ʨD_"KP5GVu|w+(@/ e)7+ۀ|DԳ\HpFQqB uHnʙvny7Y*bpK}lHYޣmu9ݨesή,Jw&kd2##`;BK$[ĠEqC@1 Hvdw|;UeYtByTIoxeK{!4DhEPKہ$(!sGħr精|'YE p!̷U re Kԑb *$ z`T@F[Y%T^-G1;K;u2d̥͌hLANFfz1 jbRB9KQ!"t/CeQ,}L 5,Fǂ Ql!X$D|v$0 ]\K九5dzrFXG^&X3Aa(F,OkT"Ϝfw[s2(TH2Y?$ͦ&}vaFH;@AvqdT{¦%D00/L`:yήp047%2)2$)>IBI1TEcÛ2Pi p=E2wD-;'̞K>Pi9c!Е`5'A.`E)~תlD;" l)fVU>@"l,ӮW)"Ppˉ"Qڿ$FE,֬-*忺EMɹN'QP)/+6l9dJDX}W!%#*Df M>hG(NDbӐ8|;Ҡ @QHoR\T~y*d+dgBƊp6&#%!Cv^nWWZ/(/FM@%3ǹ@̂|eJeV]h‚Xcy`#ҏLNhj! ]~2brʊRⰯJ4%~><)b(nQHr}GZ +{dv_ ה0,$\>˱W:Xgpi> OLZ v% Oht}F '˨RqM)A!;LСQ4 aCfGյ -,p=F7r%:zBKk_>Ăe-$Fz;(t4r%(z%ke3E;VQGB>d[|G pmfZi` 0<*z#*DZ#G/B4BJThcFlEIJ x#(v#΍\), P 0\q[Ied\CE;hq̇[=J ЯA'd$ cpiL8cGz(igBH`NyYZ$ whfg' A=Ui;;6<#uS aqO%eB~ٗ7Vh&Dɶy^ *QBѩ'4Bei(%Pe16I6;ѱjm@}%J u;6B~Y0$:3oQoܡt" bd]~J1_#Qk@ZnH娅hSB*Ѥ3NTrΖ[6,Q'F-Xf)ޠ*8;jrݙjߞӁ#1N_ }a{!1eLakFP{Jͻln >Eyu2qOӢ/ 7ckT;.@DyBnN)XBi}݃>"VxLڴ-TxΦ(!C'> E{2M6G;1敵_&Fhm6sBWҦy:<:O?xY(]H^БAYni\͏ZF\ߠ z͚!%7mp gdp`QL~>7 f9DZ*ZohP܉e"QeVJѼ<3{}mBZ/ۢe0cERNAy ˯LT@iv M!ȐJ滣)\vBuGrLr}A={B{^/A)NѲ$\Po`-lɎ,0\,]NM+PguR}AJRSgwÌr¶6)qcmXiuha*:eऍ%L}ٙ鹙HomS.$(T,Zs]D@Z}ټI8hۿZ=*(Rv!EhnYDjI)>q6-r5cp}e^7"Aכּ+qa%#'y(I2M r2Va@0;6X,!`YĹ20a2e@6MM2n2\xܺY0Pi&a9LNN-5?"!b F $ _zؤ»f_{!LP^s,8y(L.z3t4mP1 اl@ olev cC"R!Z}zo U!>AUa2PwBڐ7"!JZmؾ'="q"RvZ[ @/B 9R;Ydd&U-m DMO~Di" `EHQ;7w1#wZNv xW]=?7U~]/enʭ#(_J8YbeZ& ݽ"5y=bC;hLpDicY9>Sthx<ؚmM- -(Ƅt,`#t`##ALhهc R9]Xo=aPAK8^ѥDBOLoZ0Z NfJViaG犺솦%'9ށ=*o3ge${Oe~SKB?hwچtGMHĂs^;rd߽4;`J*q]Dvoo-́ibDIt؝Bع|ƎΕk!qو|Rxu fs Lw^y7qO#Eʕ $4@ީSJ*TvTYl1WHxh Q]sL􎱸PEqkEC=b%˜dsXď ď&΃]0,+@d!0)8W͜?gAl)HB*Ta^Vym췠5Tԍq/azZ=a?nˏQ#@S.[|V{2wS'qګb@=Vm:i=G:Дq)@SKʍ4'q {VLu>yGyYַb>)ə~njwB@M"23ڮǭ)PېqKGN&ު(@hjI-4{?veIyMιwΒp}ex%/ Hx#UΤ"ě_-;p9[ Pו7,)v.+VRADb7IGHE}JH B@ed5QB)y*NH{Ү0~1$,"׍pȑ(lÑ fx}JC 'Bb7BX+)g%CIW!J y6_Rwӌytn=S^Ve]n@}S}*벼^3ӓOt@U*+6tqWܬVpak2XSs>RʼI2Lo,c_1#w.Xݻ.spϊ+NYG9'+9s7Հ~?;#yen ӿlF ]^m{tܳ8{ӞB&E'[{\SwOMbD.P)=Hcr!9񻏮{5ۊb~VzWzx'3kH}vg~}_|KGUV2nлXYuTZ('b"\S!J O- C1*t&vTZJO>}VuH3`L ϟ!@HS<$+ ~rRX=9ydq/ʧ2uD1{y S/)h$+jMaot&gl(:$yHZjɴ+ʀLwz@8[ ?"k82%)liNpa31)`."*zNϵ`oLC\]+SA$r&.)KhfJȃ lkvz@54g3 'YE†E8[$J3SR׏Yp|>ob([S5}Ն9>~?YooeG nͣ-X'7tbTLҀ %dr S a$<,D8'[Ԛ;ohM e4S^v͸{$;KSBCM}w Utmϖdˆщ2dpG>8<|'-3]eO8> A:~.<3P *6a{g^|lY7ƌO=BVb1lķTvF[M IDAT mpsl3W_Qޠ*7F6f-wedv=fiE8@~&>0dEx>ǂTޔkEUלtܠm+jr~5O'6geκ՛JzU='y^_S}jb*:~UW;n-d'/>重;}moO}14HґUuZi)Dhmf0ۂ&e_Ǜ?S>6H]:4<iR~J+Nkn:v7Ug؜0?neSW*mlIywGT,L;竦}7Њ}q3y.:hxK~{;#Ln&*9_jkr^|Ss5$2޷zZ3y얯6;;j_mjMl*-oL{OT~vS7~ДqÓSɇߥCo>!so1|x6Њ]qnCW{yA;׎,Ы]Eim@em鉶ݫOkRaDܲ=FuTI$R, 7imLysC^vg}-m뾎7>mpI_/Z"Qӱ=t'?wf9thا[uF"o>}7zb_?:';zvx15W27ywِo{k~;A[[2f`%OohJǃSoԕ_ېa!5ũ LF׎ZPZkp,XR tS4AưÃd&|*J0Lc&DX Ѳո"-DItIM;v".eJhCXc@JD*! @ΟG)3 X$;&R)4h~l/kI-x0%2 U@G\,hyj4=1{W~G?<5>o=;+6z#*jswygp<^p7~ҝ/)ᡫ߹%wwZ d8Nv2gu#׼q래;)ﲇNR ޘз[~`'w6xg6<^?@A}cRL!Jq8}ϧOJem6+|/=r!|opIՈ>~غL_Rguo%?4^v62@jmK3 "{̏ )u)`hhNgr_@bzFة=X˹Sq<}+NYuR@u%O?:gD@3.uĭ;~{o?7U]kʪrGn叾=a>s]/#;݌F2JBS?Z1(ri{YGNCsKf0:{x/]Ts ُS1Wr'uo|t7>9)t 5f齋_LJ|zM}6>ޚاks7ϕmO/ `eT}SΜ bܖdlTϜ9|s? uoǥkz4/Hx*1ƝsԆI#T*v1% @%bA?yR@m邿ҩ~ ¬YV"7_p93n55vD|Gߙ8uCj]/MI1/ {O̅r 0r*9i#t$)lđRROtɘƣ=!"XG8 Q=m g"\|`YK?@ vPD`лAa 9FN-ꉹMD仜B2$jߙ歝*$ PVF-ڼ_@[*v#zܗRpn;loIknv@*U~}njmCv';uG=pߜ(\:ߘaGDWg&S"yBHbe59ؖ6dVrԇc`w̺ߞfUd7w^_49n:)̼욆lؤ(2[f~;yoGޝp ~כ.[WlnK#cCВ`u9M,+Ԭ~ G㯻*FAc4jr R5 {dֈͭd5{u rlH{i5,*8b ƎrW}F jOSp1 ]=8"*tZ*CLIA^t;;c#Ϳg#`+LVig:ZF50p6m RQ4KO D4C21!i@'2 9Ҋ㟼eO}h (8576i*ŕ d ppI_Nsa~'VB+;$id< b4X_ܚ@xE]3aw/t/x*2'hY&L"t0#-'I9)?>53?ytȝ31-R\C/]7ԪM݄^]4ݥߞRE& ye?8-'%-eGfo.ɊO\)3NW̚ƻSG.u|щةd5@@-YEÚdMמb-E 3Ɋ~-"<WOGͺfE[>%?J VXܣsugtx,hlI/iS^EO藳c׼1 Rw 4\3mԱ_-ɸd, b1]oV+F(}tҿ\󟍚| ;HP 3@>PƟ/<~W؍?{6-+-a[dΎ^_wyNfro.Z} kNw_!wF:.]3 >#BƖsx93[ԚhClT5]0{G#5fNt h6s>5g#@Kk-%%G*#ZSA+K&$& QHd@rMcɨ)%Rly6 TaSņnn5o $QE3Ac*'a4oE{^B?[;;`%BY7m"pMSQ/RZjPfihzD'yfG'Y1в?>oߝN6ue9C.ͺmE^1>sG[v M8b1KKza/l+I!@SFkkذˮ2]?| 2䁟)xGmޕ.isk %RiAZEלkr}gw^T7evD*յ2ogy]{*򒩘Ч FTr>B@ (гcnP-CzUhؚAKztuZE!V 7N]=gUֿ{eSWse2,ө^b3/=󁉃w*olNL9VV\88^tkG[٧ G1ŷذhun3n6Oچ̨m7k%.& Pe!B*efjNOkӵFsUuY=T_`ʼv4PFFc]{ A lU^e5MA^t{X`ߩ7q*Qөs,U0|Pƕ2H\A^r 1dne*K5A+vt߼4+zard eXJ0A%I2lZHlXk/vvW-!Pv(ܹsサwC[Ӫ'ԳТN]2vNjlWY>]+u/۽onuK ~ޱ+|? {S.8~c<ܖDZі(}&m\RUܡKRغ@Sq?vCpS'Ms̏*b<:ʺok{hW%\l' (k%(׽ؑ ,Dem[t٥ӿ4dctVz!?bС;i$?wg~QpSACv*X} . )ٿ'޷rAN38eo|1 ;k4$U2q]:4ձȳғD[vf+44'u:fwhWZۘQgMg}ʒ|')!"#gap7I;aJԁG>HԔ! 'FrG=X#.e& 5+CaJ,a%aw/*?%Wds CY:0{<؁) F,=ߥ0n(aSg(R@V9h5-|[| @*T]-7oۺ3ղJ<VkαԒo1>e]i45 畿9pS3 o<{U~70`Dh3vOON--R n;-}sNВ~GeZ<?=}\q*lrU^7\"px w\EV!*n|}NܳB^^}ÿzc$[o;m/z)WqIN۴5\u [rDoumJa]M8lDSɟoA}sMҥgPy E_lDIZH>rg'5;#gܶNywa"-u婫vNoY1 Wֽthm}UV^=mRm_WHo-"]J4=,2nB1Xoy ӿ~o9}y%K?BU}+ 0odIq 8MyyX?Uԡ~u@[{oztx,e7|WE%ӮBhhJp%,|3't\冒2mF(ʛքߝ]a0gV n֙f{@@6b۠eӞk;>K?ѻ cg9h7PUߔcz}99_ v/oZ\{;5agGE.F" ?@㑮H[voѭy7WJoMJ1eTorClJeX`bG8FZ$s"s`gGΛ<{mj2|,z/< {wR@؀T6lu.9q~}oeE]9Sý~ GdPVFۃW-?x̿yO']v|x؋ &cpO5% =\zWO'PMg^VyoWy/jUZܥC]^1CnK⚋;cO$n@szIQ혁{#%wx fLN=+Ya#} 7XѮp(%c78zRLK?ͼgzYMn(D;8EHB'1 6XW cb1/;y%Ϛ֣sݫ~< s;j{ήex˻ ھܵۋ4yr:Rsg]8HK>ǹ%Eh37&D+GIR' 4!򔇫P!A{ "8_\a9 S~!R۝F/NS!DzkI=t Ha5gX>vmYK)H(KR(* ݤD8;ݕ- SV/ IDATsg7z gXe 'r$?nȨM#l3mJ"l ƒ̷8g@@ͽ)Q[-0sVH R1yL TM j.l3lXGhuuۋZ2my^I[| 4텣{vRڑ[~W)n9}(hMƟp+ 5&ڙҒL{m:|c^Ձ?v޷lGyYoM2;&75RHjOE> ]Amht Jdb' &tPviNFIeۯ&#‹ƳL3,8et;TҮ"f8yꉹ,s}SO;;_u^:{ki@ZDYhIX&?q/ۓA-B\G`f,0mT*F\9Hd/-~eQbB R_L#cA|eʜǀ?~Jlx<3,^旛ja9I\_^e.A-%!U~k:CGZ.% ٿDJ? /`Ǖ%] Ѷ~38Yg:@LRPuq3Qr/e:Bx́x'ĽɕyF@!tDEɢmQ"P7؎d5y@Qvz-IMq; 5NA7,XS4=@(;1$ KEr..#lM % [r0Ay$#ߢJ3^]kAT(Ruɑ^i'#3P*"R+A@c?,ݧ N\0guf(1!YPF힕[x:AIE3}v)YqPmHsX J \Rn5mX]̡6I4>.fz$'>]䳆.8sA6g&t\ag`ˆ+G"VMB1!ډqEHE6¢zٛ#&hM$J |]r388 Qq=e(a&q!PQʛwY-A!`2a4"2"g$ 1QY1]N*Hc]<|xd #bˣdH *̜C@tCCK" R+H>-ǮDF0ht"c~MJ֋"4`'ID5T`e%lW*1]ɔc+eD|(o69ԗa4[7!H7,ƢB%QL-V2(ۄӸ/qu Xq:@7R&0I9!Yek"+F준&JoK -I)Rԩbė$Cr)z찭t(_#]4oK/5YxPsBʆ߬-]A<ڭ,wbCP@w {/89`&4آ`}A;1%,}^>fXBT6 C_) &2{|(xIvxo(XQеeP)T+Jo_dLEVd2EDRp 1Dai?#ʢWJ: ^sSm5Bpb XYG_V#l oF܉"[d'hW0ȃ C,I<` &0NZαNFu*ɨAc15S\{Qxzub OvϩHJI u9Tnk疾(CT*%^ЭǒNE w^Ed t;4?v+` TSF u!6c9!FkV&iw [-pˑ U<ιst|A_ Y*yCp=QO;! ѐfMȐvln!Ohx nx`%ڞU!ϯ&# 1QcFd/Q:,`Sͮ;F]I>7P芋N<9Ҥ IR) k4 l8tx.lu3jF7$3j!Pa҈(" 6I5 &b聥$MDQbHgTQ4XGK E[CA |gmDX@ ET+^YZSn \ϖ*u-0XGD50"dt0Ԓ#hq Z qCDK#(&A+NL*+G1kDlGsP5fD$xIb13QD$^qK 6 | R7 k 1mZ 9 Īqk\Wc[80PBdG ݥZlEG3!tq*ˆA+X,EDZfb[PBafUt£jYNцOOѤ &#SeH@C_# +o" VbM4xqİM04i\ODjhJlE$0Mըʅ3K tB(F }tЉ-QPMc-"+1A\ @S)~+t& ƩL!mvxd$C+R%J ] 3q@d#En*DD:-`LT*{(Rl棲fSI'S4UF?}ehc P'UnSdl&_r`BIbCQhOI#(tYYd9%_?]bsG%QlـNM|R]kiUr(qDDBnLX(c10>rɀ MfN4xm9rCjLGuLwLԎ:WV0N0/bU$[@Gc ̐t(ʘ4A{lIRjdstn\X8׊()a=D/.Y$T~ζbJM,$-1nU#6\"(kLt`cU@B}J w̛*"BEyV IG,DCE'|#fwldTyBZ֣Wr%,i=fr$ܵ(U.ᲠXQb̢ݾ*Yaܭ`$1dԁ ^c<(=asTڐOlȈACaF+8 \Ì*GVUTg򄊘ĺM W䑭\L4[+Ii$ ɞGF1(IWҕ/ 1].rK7 GYX6֍"bFvMv1ƥƵZ)Miɯ > Fƛ˅N8jJV7pm!R/^"D'(PZ;y1 0C.Dm/ٻiogppSpk޶ٸg qዼ pBd8)Xnvapog˜h$bi(#l LYٺ_)[ qjF fHnl6HUsP=4o/5'k@KtBY-IFv9=1 H01"')d1<ΉDƔ}|a-ǙU AoL`wTIhBtLL {D` :uLQkF=~ ۪xHp + juC`vBLWN o(YY+vx.E9z>2PAZ.˺!OZdP[,;n$<H|0vL{b{r\E&i8<;z0[`GL<:X$>QNrK(MBZD󵑡E$} v9RU0k2QEk2n%*0b/a(KfZPHElXDZP !0PSN1ʦ.d]: V)a]S-&CQ/#YGF@J, EʤK)1bR 7pZ:`|Ag֖+)|IL,d?J ܼ%Rj&p|R7b:t˿ 9MzTJLwSe)jl|ƑQz-?s8\K!LnpQHP̔"x`;Tم) F+ @m+o\ m$lO4ᐳc[i0w&;{A*tO I/J*ɯXM5X'r~:y9; {ksƯ(N>@SׂϯXE5mGS}Y!Blj ilC0k7^ls`m&|w|y{)`yw5)F@ȧܓCaL.IԶ7_ZBS{kWAylM0 @8`0om4 ʮ`I} 4'RbOʅ$:vadPty*IQZtG(/q7U$F&B2R1&Ai:ʸJBB zr/0+1# 4>LDxItUtϼeT7FʳIvޏOIb_p0"sI3}P bmu)6QF~c INc氊þGdYÊ t w,>׺8,&Hr։oZ8Mdž_+0%ԯ7y5Bw`)( !Ro\ݥ-QP;wz{&A1:[>K%*! a'cyanُqSG5d& A'qƬsfh^Yi& dJ*&YJ>v\s[Ȱ(Ի1: .gTdy0Q5 #Pe:H*V@&@Co {yhs-p=v\ цUm\c!E!Bыz8>=%g:|w#:-pv{j7ޞxl Vd ip}P+VӀH=\A>_ OeGDǔ<%448INKwbk5 h jڰzҺHJV\Gu;J \A0 bg jIJ yylhZtʙ$\7TwݢBSBW9p1)Ri/w/ѭOQQr"ã``Sp{*`pt#g0Z8Ka*G"$h .#'*@9,)a:]e$KY(W!c6܁ZԄ3F%DhEzE@ PG $9,䷆@ŁoBOjPE7IX`!0BJIWB@u$^DD@+`KZIu+u=P GVnhHsR#2/E,`.T)kQ{<92K W<1y@gSj۔$R5Tʔ%b=$k@%_H[xʯ5dNmLٗ_RWbWE5\_GECGm%L8q+ŠJBh(PtQyDe"C,,5OjR="㭟#4܄]8ޛi\:_$v̄xCF+Eܟ,!*A.z 7@UWj2hrE멬'I$rԂ"ozM{/9NHmZXQcq$C '})HEXE@vV |0 w[N4Vf%ރ1hgI |m,۲x^ !)/P@&`3fv@Gk(?܍P wD\u$Y8+ {L#q*Y K+,dV 膊q T=tz]QKݞ{8W15,iy5AʇbuګэaHl/A簵9>Ÿi z[kzJC︇@WI H4Dʷ*kMƌݩ*h 6гRCD{tL0w4AE< -ug:+@x.sp t'sdhcD"*{"H !;F3ށ @v2pZ5\xD 5v}p S\grhcM;9P e=ξI"\dF̥c!pV(})th`o|a:/~x|#AB8 ='*Jh; a@3M Bm[8<1LoL!7@ B+r%xh,նBYwHe B _/`OaqTެ`8"'{ d(vvF#QT/d$x$iA0cyaeGaITFKFf6"ZD*h9"ܠ "r,X=$$Tt'< )I(Xl tTa+`qڰx+*o( UQIK6rdSIсmYb`I#zTcjA,L JLXb(  ,Pӛd}DD!Jf"{Yu9yư~W nϿErB6Ogoπ/ج twOQO=ҹ$0A0 vTz/, 5KoGGRU;"֙痭1Em˶`Ge^_6u< 9;{ZlL:dW0k A[oHN*P?M fV{'Tt6xx4`gPSpVAgqnxד)vNrL%Zƈ ><:k nqu7Erk^G2. m:5p`Iw7 $4A,w*:H*@'tG8~% Va9~Vľ-MҵA E0_KW\5ڣJ#:ʏސRoP * pBBGH Iá2aso<2JQ;2Ȇ(IL[qL6t̚T5z"PT+t:|si4NmЬhDQo_`FGyLs 6"\DR;7#0U!E$4j„*V (bj lE%@r͍7O ˉ!WR ^uZ`5sbEg %1Mk%X8R\;-bPbP7:d0=Byl\P;@p`ԋ!WdcP$X2LQ0, 5r&L[1"?U8_n K|7eyqO҆EnШ鵹 =Pg0Ⱥ;$'*&zj+*0 # Dc゛@GH?rA1nmwW[:hVЬoˬYFZ_*t_y$#ϔ,5af LsbI̐DrIua4Oą nV>H!+X3~}wyLr |(r1\n_W:_LFDPHB{03<Ep$K_d 6V/!FvNcX/.{[$ʄ]18uŎB5e⤾)_CPR$ Il BE &@7 1-!gVsHFQG'Zy/xewr+=5$&v,s!2TC {˔*[e ^1: m ҁg?juFAJPA;uV7Ke ,zqL21LqWg(d7+~HbAhb_W1QmkAh@^bXR5 R|*_Ȩni;Ӆ1)J9^pF$ճ= ;Jtr_>(]M(@@N拽ib 7H ^Wfn#vAu8@P?jURԙyK<6B|^FPi%jH$ec'eI,tEYPJ)@)ubM:"Uhdc b@IxlHDidy ϲ$^q O8pB@ңږ៦ӑ֑ 7m]㰍2kb6:IBNqdwpHa%!-qɇbVР(/5b;d)1I,dGS6VD IuTjTr<Z476BAL[o%ŐTVYC$x|h8LMD*$(lLŘpf Bi"-0lV2nQJVDbekj (T;@|/vi ts`l nN9: }uFVRIfNF? -'j]HĿ:UXJCmH  &f;zO-j "e\*Q&vD1y**1]iSdA @l2h\,h dY.^V`A\1x1NMt0At|itSj @s#usQ]b Lr_K9uKRJ9?&8ߓ1q ( ],g([(tn[x$%rU"=E!:?ŎCi<dؒ 6ouBgۀ{bJhcKPDž#Ocɠhj)^ 2DvPo`,L!+񞯄6GZf&aRmTD|щ[,!JDmK&Uj(0Hn 3{ܗD4^5ZcJ1) HεRO$>`ew;l%1J &Fk07vN8"v/F * j_5J߫N~RDbeDeie`a2}M%VOzhp;Ԁ!JI:+uUaA8=>P'(c{`HIе*&9$1?2XȆ!PXPYņ>lG hcܻ*@ % ~Tޠ*7A j +XkxdnYbRJ~JP荙L`~t@k-[PJ(Ʒ 8+mz<{@yBưЫxMq$]hIaAx?Kr4t Q+hYh&AKFHO0a-?5UH@&VfC_>26BG<, ?Ą)ݫ8eX|pCn-,[jN"KBY̎':VU j eOU<X!IsSe+I$(U ӊYZ^~UΨD+YQ7/vc81Yaev!<X&H[9+j F2ȍ&()E&Mz $Wd 76dsN(y R3P#iM9YWAx ۺ,KؚA4j +8 P(E6r $('8r ,t] gAqN5d%v'b2xG"7 EsfI,I$,$Z𢄻%NJ%,II x!Cz5XvQz=KeJ"c! dE6O>.˗pI7G8Ԡ OW0ǭ|o!$B6I̘Q0E'̔b艈 El?I QeY[ Cy`udp/4c as_rkI.B2 tI@fE )}Yل\GĤV02~oxc-[BU5R{DPk#ZP7  :];OρxI1 Γ(cb]%qFgl$։JG2^bðD ݿy갦{&RѫҢIGRŽ\pnKvםisXugҀ0lǯcǓ gV3'WٌҢ15 r7{%םi,@; \@l}c)7(Mg<㠷!`R/{T 4R>nyt؁{@$J?-{cPMw]֝I \[O/oPC{2 }lm$r);@1h9 0@Ǟ `dt $%4В2ڲc>dY4 wY"@~-*ٿt9 q[mIOӮ1_ռȉDc*4,$QTYNU_IZ%6ϸ(F,&Kխ^8a񃚦 =74~urƈSG*Mؐ-!HTg3D5Swt[U&J9>;Sj͂ '0gԴuC'wg>5sĩY#O3 qlhcsasf(vdId_}"/H{UIKW=wA9]ϻN."[+ µ~󖗝=?{功RvҢe㎟jpLJִwecVd̬Ub(}?RjHW~]e]J.F TeadTd Jy%R(kŰսO_p#/fF}Kk`;i#.JZYV0# *.fȰ`NZ \Z9KaɑB?A<-I'XoPC ѧVgJD9E葕 u!?d+ Q~".&.ʦN%cv"f`Zх9Ymsƾ?a,eC1Q͢R0:ݐ*0D5ɼG:\ucF?]LJnk>n?}~>>k?t%`cc;E\-pps7y籡68V`BcWhSѯRg$ݵ` zl%8b̀ ԣ!8 ÚF<64 ׹cA?ց1w&Nצ ?;^?8zXmo+Lv}wdNV>ϹwѶ{mW>?Y+W;r#s|Ҕ̣_k1spp ?NXghQԛMm?6<+'.o/|gpC9ɖp*z~B`\NTV~RQL <.K^vKM+29Ҹ ,' i i3݆xLY&J[IoAB)aeos ;[YtcQs}G %lo@"u/̄Ej#7u +teҖ {jzpsS7Uu֖u~*TL j6OwnA;?"ubH!!ڽwV]E =TE:3wܱtɹbaNv83w }G3ʴ*VAJ237fVZ)IѲJfm;؃a[X|3G#g疛 \dcʽrzêOӣ:-H H~39t߷[R:HYAMdrD vIw(sUp3i DjGj`f./"}36)k" vo߯{ 6pC9sDMvR.ԶS_Ī}zDN|Ռ!m?M\JTdę(=D>ĭ?ahCd(V$./d jofe: _vxs|y9CBw'I L.Wz'nm>WPhn@x,[8sO0#|yCO?xĔ~B1qг?_\^x͚Ć$͞'aD1bjT / 0j1ٹV=J&k!/g,~ݿooV/]v~g"t~TgMaMB.Glyq;6n.E3~UyAG5c~0ݛ$ٿme a,=Nrl}o7=eV4i}r~}6xŤ÷6Ko=Nd|OWd^11|31\|W $Ū%?yJmG/.w?[^sG$ v0$Dˆpi) 0H.0W.Pꃬ]Vo7n牡]ڕIweӝbpmM4[!uvebP -[A ۺK]tgoQ{Oq~mSX4R4KvD+$c-%3UA^`pUxl)wҝ0 @-5$U`ljaziE&0YILvt%E]Fj)wExDz*fڜg0 @[wiW;: $JJWjK'-miyj@_٢L_PlO8+ƀdA,E <(hnu&+{{1| zl)+n-ygw疾ԐXk@[i`xc 0BV-3 %`_} Q"ۍCz҇.8]:ک@ 8t?(|ퟹfgY Ux%1'R^箉 H{̊2;ժE~ܳh[ "9ṡw@|!퟽fgc䥫~r ||N=pb񄣞^6eW4gП@Gk˻~rąѳq""Wr⫦:Q~O6qxޘ)/?]]UI{>!d$;Zهo;Z: 3}5u}_^ԙ)6̯?Wਨ?ǣ|w=]Pʞ}b=wu:a IDAT=D"AK&7.t-̶4U{&S7dFֵ>Ej{u?eo,ɦJ}]2o @zqǔ4rݥE9i-i.UuyP&O }&@}/UҖ҈0o,w4-~vqO.U'L<xΊ] F-9Y۳nqO+MǷ6^ײpLCy:q/-;ZTo>u4,Ougz^q*ݛ_ucudJ\Q9aHݕ9a@Oxzt݅ͧw!o\WG7LIKwp}tߜķts۞)i.5oY:󽛟Rn;Q`pԽ[qw:3SO~?i%.[o<9lc;vS2@[Oig& LIkOi xfPHKh)̤+:$ĒT}A>c\[^7uo!U^]O^>2HO!mVJn~[P 7#Wu͏_J锟k=L:Mp|Juή.ymq^=tvwA 9_wi% w"4 =~믘thSMCs?wpߩuN 3_1w?Y=?Imo֝Mm87o~7/v;ִO +|rpǚ@Wv""!j)hC@ǚ }6^Uilцã~v~{Jzs~w&}-N{ ٽ[~L>Lч~nnG{;ʧ ;7l.[gxddtģGlӃҹpXCM$$csdF].KgC}46שmsГ{O;Zzh:*sGGʦ 9_n-"*~xoxݿ?{S]izk/ 3̼#S}cw d̡'RkWlQu-11xGrʮc[8fP"dTO}'+jlQGl^w~rics8UA_?0c;`ޞ8R]U?ٷwgIBx~>SZؿ<k•n<2zÑQyp}מ|Ot"~=}v4ޛǯ;rpڐӎ#İ&{C㮞t,Ȕ1;} ~e|j[+{‚z}r BlG%760 4OS'qݞVllq4=ya)t\ ?{ś4|oE,9o[/y|%!Uo~vM`ٚ!U'Z+j|~猞\_bGTڣ9,x'(^8K|760 $B7zljaι7f Ԟ)8Ű}_jqC z3mUY?coT[rmom!5uTi݂u δW@.HeTwkU.qola44]^2O(](e2!z+4m%Xj2U!:hkTE}[76DO?4{wz~kL/\ bB.~rӬgMGO.]D & !kA_4tOT'mW_;UCrZc9T[;ϩip|SmHuݟ~+"adO.uŤÏts%Aa-+9vSL}jr=ۿ~:J 60Ԗwre+o OU|ͻbI;O K+2"pw+VxCT:aO$s67ɥ?Ms' l(ɬ;2\]xUDqcBmչ ]Cǁ0Z0F2ݮlqi:SR8jSQӆ ܠEW V}u*WTU:tGe!ʐ"{"D>|\-3?7i:߉ e_`1>4ysvy>d_x;\ʏ~V<)Ӿ-a(htADK 6!o@gaCWvMnߴ'6Rv何;j Fo4 8=yH~Cw=nik.*",|ɦ~?~owJHmt WOÒǜnT, /[({&3ۦ-xǚk̸^"`<7L="+Q9 pUbr>m{O _Xѩڧ\ p]@0T04m忂l]VnrG&"ρP_+#m{O $r*;eD BG5;:;X_m{OM+TvEUz}fE83jO*bP]͓x謼nY!8+FHWW:O޶_r@EroGܟQl@Q*X8 A7HnaUiIހy_z"KXhИ~=87>V +׾,AQt]fS>cqGxFP8tĈ _0"1C0p (&A!gıCE}A,~Ól>F[#a!>:T}/5%eA'!l3^3iT *2q6)7(/6{@ޯ'WtE: -?x~0^8uXSEINQ$7R¬b/(<>˷tesyOMy~Y:Zfټ{ hEp_-{ ;[^͉JzK# Bq׿_ʃya!Ed@erh*Ug~J#dj@D}ގ/GYj4$Ok<7c{Ţ67hQ2TO3҉ cyAk0>tgӠzrm%-ZF;uHq>npdє͖хL6E ~0%j%PC욘 q|"d\+$sn$9GӾ :̕tW>Xa TxuۊT}9 T.毘Jۋa[R3u DD:;@r|^(;K|6J s>E7y]\9?_JG[g.^Ė΂d"^[ڝvΚLWs7i͖"{.4=Vu4t>͝}^po ~§?qE[:||d6& P6\qNXU|Hӹ}ū?z%'x9ccug&udh&|D sIl-{Ė5\9kq;l hڈ^)n۪px֧~:g/M\z.xT R]=s'oh•>=v;ǘ3L:-Ng{r#K0ٓNf=]T@]=ms'ozdf=v;GO ~ΪTf#!2Mi:K7MقiM{b;,Fڑ԰pgѼE{︖‘zkjwgSۊOee͈0W\{mÆ9B !*JeUwT|{wQ;n \iBr?<{}.+J&>LA*ӝUI5swn(.Lew7CMˍU)z\Ձ\[&9a0sXea'_.#7946m;_sqA}' ;v쮇ޜѝ/`*hn?\PΔu@IAW2D$.).J+/_3dަolg%}DžKNbJPZ⎑~3o5菋N9o}w[F[~S?TJWҙ\5Spږ0q1 +wVNZ[teR9_cIHf|/~a7?x3WUů}zDC sx`{oxI[*|7㴥*n{-uUޝg9凃 'S>' f~ox%kjFb~雧-tzq͝_~c\~y) IDATS&nA+*әz _ʅko\/Qœz"V5 oh՝T~߮~LZ6NfokmU{OP^/ƖR Ė MrЃCsʁV@q|{ȽQ:TpGv}wڊl(hԨuT>z@ÄA%eYZ?WS;ͥP (mE};*t(k]m'lIoDSRsn*|ü%I=a:N!vgG,0ȅAW&9z}{KO6>ԐNw^'.?q{]зk`֦"QNޝFafYמϧ.~h55WŶ0T{ޢ>]Zo(x]>GPkXq<=X[k7-09 "C^M;PM\O7FW5n7Ǩ[3j[JϺ+Qu5.f!+W3sg & GHd| Q~\3os jS~uɳͻգᇵ5.fKme7xYrG{z=}Wn$Tj MIo|(nݞaW>tt'o Ӈ?'Dwv6+nBWį녆ݯ=uD""6_O3!9GGnUIj6]Y=MYEb"ӁOTUӟ[}L aK6MXI*PP)lgs9ᕺspu1Ƀk6]t^᪑mVqET:j;yӣ7n< ?'jMc[6k ]͓^!,l’&OT`WC \&g& #* jZ\XTf*>Koq#+&8 }몃?l#+bok̳A?{X.D||; Z|hwOvgOj_~̞h;\UNNdi]Y3W~yLT8&_>}灊hl/Z)nw'smb kfu4v yqD AmSYWOR'i1CYYk_(|h[[nyڥJ {}[-@g[Fi5z\N^b6 K_x?M/:G5G[l;\si˧UX}$jh+Z#P'9Ё0ׇϝ({`ڋ?Lv*0Q5+.:fN uThh8.'E͏^lyx p IO?8!,/cEpW$]&6k$TP]m^XC'4`|!iGC"CTCS*ȕ{TWY9ˏ,tĆ6Aha3r,&-qjIӱtX6Et @!)K?o=r{.{篞lۨbȓ/y>c&y ՂxY(nl)A:]5 h|]r)pGw@i`T@A8"R1MrNb~EUjU .|IybH>_AGl4Ўj`}.` Wx~4‹nc+PC4C,6| FFJkGGP{?đK S1T+hCaSiH0N8IuvcpߖXEMn4߆G}ЩU&$ D&fHsz!P+z=䡔Ҵ(>-%izXۗ~pTߊzD7y%)T-Uwf5GE^-F̮J,.&!NacQ5g`A4asx'^ۧ IҌ9LK8aϠsU/w\U÷ajA˻dV~tW<ʥRS5l sFoO6Ha;$-r9%f7"0j)$/MDžvkII {ѠMgx s7Ŭg XX։S C@<B㭣h2ZF7LIͰ؄I6KE4ݣˆ!ы=<7L N>8q6!cuorWov:oGDUw3fOD6xa.sp#1/~ *E6ܲqUkh)w/iBɹΚ/@bD`}5N3>V d:^SsoqS1lQxc~ɍ3 '܌lb%{V;,䒤bVF8EfxR@mQi4鞱[,ME>E >\&VA,0I:rfشYʽE:rƎB;Mٚ5MJ݈5+u!H,ڙ ԢQMOYqv0=G׊qeUJ^bcÉƦQ1aa1dDe,SL1ޑgp2}K m -?+~b%+@7մ,/\zu1z͍.ڀgDi].&|G[9nkoTK+b׋.6 ~d0Db8n4NP#YGoBV,YBiǬmC{7|1fѸB|Yr|>̎:.f[pqX(Op8[+=;Ո'6k=geN43T%;Q/<*kb$Byh^d2 0;3MſDĨ& P\a9lP  :|11C\FmS5S2{sXDA4]\og*F(k `@Y_ǗO@WQU8_\Jk)ǏȗU@!q 0{|/|-j{oǏiI΅r9ʣ(/\b8TFsZxeR/,ŒDZ< I_6 H_U|*]3SFf,90߿@C-z sG?*J,LԔ}+%C$K ,'fQbc30R! ["a[W]1{݂5GkK-(ktϬ5{:{RQǍZ֕FҴ.]~8z侮L5sT̈́& K&BݝIn=3N ѨMoR؟auU5Ə؄'%oȽ;>3ƶ{϶@O4˂"5L7ʍ[ueNZE(0s[&QObA=vˈG%|!#'[ƞ^:T{%R,I5c-̄)g&>><'xޔkYnjO+mTeY t(A,1 bW.l, z ҥYn7B\~´r ?PE!q`)ăzX54I%'H/X#5m4AfOr\$2*Ldejn].9g{θW& }'*KH[k7HqxOp tJ}yO6G0_Ck <0n`!V׷k,3qg[WQ{sTgwrMLRcRϞs񟥘^ZtRRroܺ~OBEglbMb|>oL05Hezc_84ii#,k~)qSFFR7PTD]YX%Aj" ),̦͐Aɟ="ϊyLyŨ@,$Ry&o+ٗbU,e 3$ n\1{UTSK鵫,Q܅,߁!ۜJ 8iaEBVY t A* GФIb<Ҹ {Ủ !-%Nڙs[۶z.(+JX$k\V[֚xӨt+ SslpWdQmʣ (4ttwW4fV>pE'=16v7̅L.~x\;MOnF]oj 松ũ̏.y㸱5pY~ VOyG WV5sLMTo^[ 8OkX@2u/)yb^):XH̼ y{ E,A65h2)zkzSq!d=ZBU oM_UH0-_M$SE Od$dʳoWODF7w ˆY ^9cP/fu")6BuX TSsE-9GYqF4D#lOx}3؂7%E[<:^1#.b-NZ$TuB+*#O1+҄w]ċe)-_g骥Q ߻\r=fߴuw6Φq O\U]Pѧ罽dfܥo_9E'@s} <~ʛrMc{1w.YFkƘOߴ`探N\^K$LeތYxCW>*&pA1VAT 3=:q#T3FPk+Nz1K \Yl\1=Fs(COTȄ+P~]dOٜPzmL` G]@1+ $5,cŖA"B *F+LqJN/89 +Zp@i71vМxu8 2d/Qܩ댸t (ʠaEgHq*FpSga²iM%II_'Ӌ!\ 'y=lrԗ 7̮ 0#`FQ)kl-xu lsibLW>!^5$8f1=kӖnFV6|wgOѯdGG? ݩtσ>rU sWv6Ϭ9XQЙIml*BAYa}7Uut ә_^Ҷ;vysg[3>H&0Tw|#o͊`誆TWW C~VZm۰kpq*3oˆ=xRiQVJ_wdAl ǜ ho?t32bҍabTU>ߑ_47fW*3"dVk(q(-uP#;4wE6yH/ZzS&o5 缱nr:OT^Su i'﫧t?'O~gVCk./)gz?ҍ[tRyo+HsWL\QªX|bkWI6jiXXtPGH$V۵dXG0F(̖ C?7XN f̫ǃ9rICs 8iޔ-i) 3NWqt+2D < Qp@7fLsq݇qc*7"D 'Q"Ɠi˓ [`%Sȝ[0%t2,e/R{ႌڐ꫔Ě+gDd0\)[ HUP$:4oYSA2gnz] /jJ/:9b.]^wfES셳K:x<=yaN']KW/^:_|9}+g=zĞvESG~Ʃ*rsLymM^;z1 VOՠںRD"\g.^hE M{kӄ探 H": IDATS&o/)^zjw6GT~U?vq59|oVkv CҹǎoSYvI+`fT'̙o\v'U3C. ں Z:'Xۻ ]BdsA9oHPZ6cZA[g: /Lgqſ.~#.]tw6!6V5\6o O~ +~r/=Hz5Gc0 +UP1a(@;[qL.*Bf>ԧ5d47gt)؂HX^X]x-P'VǗN Fh/i:H<$nN[Ihq V59pjV>oHCBgԜCJ y4b] 78;9cC%a\ "gж 6P &4.qPL+ʈhvR"K`.Ι7[3*d< R ;fckWOSR [UuxӢlS 3k\k)}wӸ3n.)n(\{_|#o͎kswO^}k'o3TsGQ&'Y& ZJT. ; 5ٵ\.I+~q+onz!7eǮ_k#GˆU)C8Z|&(_I͐OY1v'o۸kP~N],K VOoщ7grٖELO6فN.8P`{9150vdD]s֐ ΂M(${rL.]pc++zΚgMf1ZCmSK9N[@~p+v ҡ9{XF8}jCfS.c Y[M Wjkl_K*ڹqj wAň-bb>m17dǴg./\9kv7iM'tkRqA*꠻'gc.=Cjwʤ& ;ZrĐ?-:'\_ϭ 3s+w}W)I$?Wh{8Z[]Vŏ5:LmlL41 ˳Bkd6+u{"}v hvj=鲢νeֳ1VA=r48gɌGLܹ|rs( tb,Hl:0u1JXl`} Aԍ=(>%qch 2ei[-&>pGC*00;G%d$ڴHYb+dZjCS5jS"60mtkQFD:%KVd`$ 24'֟Džml $ 2FE[9+Z"ARؘrLej}8*zW?sͩ U Mk 8gl ]̥(@AP>o(Rrh$&*a-^\iP'p@Y+5%?bX3uf/޹H: 2j؊(1|D ‹2D^"J))~=+uYE%A@xLVNC"ٓ_0wK<OCP.he$zݸ!&A8Xh1Œ2:ĂK[t"dliCF1;ll+޲jXLϞE'9uk* 󯹋׏[UؓIƊ Eށo8nmƽ60}%uȇܒZi#θ{'C,Kb26+"L12$Ԃ Qq-[,qZ1]wyƽ3 6 3(څ}t+BXT-&EFk'FхhK6OjmdbyAclfr@u%F!ɶ)hO+Al1V6@ aa (7 2:b@0%ӬkXsؗdaHc&X;yw[ǶvYzhW&u)[W}>" ǯ=~|{FKR2Tf܀L2U @㆓>g,^?!/yc㮁mMT"]I;]TrMnVXn(@뙣w]6s=;Ӗ/8aq{٫Hȡ 3t. ; 0غkˋ;|< L4b܇aidXY^e@M& [; SNzUsׅqTa`X!-hIo*=wjl/*Lew5G3LA2[t|@n~s]^x̧njܽ j,xzٌ;/^Y`͔L64@UisMaEP|F%ҬhrBfz(K"̇}8j DSڟʘ.bhi"8FF<5n+zZlOGNb^9+lwm u@uSAB! Zl\av9l.=8@@ޝ~pH"_^}]ϝ?>1!w߳ nkme6I?|_{< m5r /<ֹ˾4Ctu}g?<&Fg]pQh3"ve1h7`T@~$A*r '"E;M2.|7gzU 7a)i#=K.FڡPn|O-i*DOPR7H=oH*$Kßt%>JF0 HbHZ8<`PE F{xmgQ]ԳtEj^ & /l\exvdMUKm!i}S`U)򗈺`\5 `Z[Qlcq;9}Dkoʥ%bUV@qy^Q< (JS/Kuk˄q^rrbo* JXacdCSp{YPQq/[c8A. eNT^6kކ;,&ǭs^~yP\xR/?DWjK7\Uvץʋ;ʋFo_Yc }z W43zw_|򽯝| 5TI#U S>S YJċյaԖ:u1N?L{/X@*?$v +(xL vȔCGfȭbDEb堵,Q@Ų)^{"1nݰZC6)TK$P_JuW2&Ŏ,eބUnbf\qߜ=qUYY/ عk H 8TL^ I2%Z"ߖR ȿ8RŘLu ea.ߡtgK90L0 X~ߊa{_[;e\y=m=(&/@GVSu} OYS=TcHaNmjl-s؏pV=} 'ji5F},LS8VU<*bn#><ϟشl"6Ek7,.s*O+콾h;W4QJn0ڢ[Xs:TEa5,$bw HH-2D=_' q2W@YH7pצ- FަЭ]MkM|D/~1,~ (GrfoVC9ljb2e: !A F198mS;Zg*Xs8<̱C%VGq,vAI |-VAlaji[ҕ[q*} 2?&xL;̓RazoŘ~8QAPL۰sMu0/:C,R6\uPL5\fOֺy W0^\8MQ#)1WLٓڭȧɰYXp-q|GL9pHw|sk1].=gO/b޳/X?cDn)ykCLLuYY_0u^c bx^3C-ϠRj)Nt<*-I@W"/jYP>@?tu'h$8A; Jԥvi+d0Aނ>-$>1ʐz\/Z/diqxwz7eDϔ(&btwӭ(&4J*ڐh;Yk 7Y8Kq+M /#AB CGcAA9liNumI1aL+htiO5۱C,EL' DkJPD-Be;=];*fC)OG {ЏY#.KrbX7aPG(Q3M&c-18Z̠E"}vA(p#d Be=j6r%s퉓e BcRH\w5X'z@`) =/!:TEM FDj l1N\imBLz"T!p889E5>83 0YSв{Ƶ T@r)м -J%bHE.gyhp赸Q۱&.X\yN\H=QY פO\㪀I[ O1Dz PiQƃ>GD55'c0_IՓ{2>C " uX-1# Fs=&bL(WovOqOѤDCDakAOzaLY-,ٜ]݅i^>#NEt;w饊+B:@Ah h8}tM)Hb @HqrDEczN[)Q`!ic|'Dn3i4&64+vQ6RvL 7]V82LqqܝfrJ4&I}l^\hba0pM glGY#CȐÙFGb=a9Gۓfs1)8I9ڰxj~唖cTJ\zlSg~]jcۈ6s؉2OZ\uyB 04pShlǂHmvYvN^ aʉ~~{!w:2d\XC .ms:"U^yW[z,sudIQss?z)RQ0)Q{ÖWV8V!+cg'ZQ)eVH1>ڈȀht@Rԇ]@hhv.T$4A*#NÅ .̌Q,UA69JL -"/L~{ΑT3ikJ+ _YU 3 %F-ʸ+ mkaXdFO ?03WS JqR|p8'4Iܣx9rpɘ vBp \vCя̑3]EE=ȕO n 縢s4 3S2v#iH)DQ,g(3"Z1%Qv KG8!BvTDϑ\qȑogRn@F< #<y|9F?ypR`ݍ(ks8`)H!4@ڢI,GfFg/<"rݷļKWłc{bΘ0w5 vнs֠@9x£~e˽ .`\  VT`)Z.BM-hZC\`s ZxR7q=$f wo:҉N - -[MQ/!KE#OxA֍1={Ik)< 3p{ $^ ƢUw0z*bK ^KcEdp$Zm[GZ{bK0lp!4j1V rȄVY֜vi0'yFڨ0.ah*Lh^ hXXET Kuɕz0lb;*bRL# ey'M$e5 F)pK dz$fwPU.a.{ѿzy\4 +"Ò s¶h(v"9=d1 8GyN4qR#Ԩf\($+J:'9{h&rtdЩDOA76>7 IDATMNp 0dS=)T[Cʛ hgKSVQyURU0ap]GWP@WWVW?Bl[4-b}em t3ޯyQi 8D,WN6ЊXi8}ghC~To:^0ol+"Qf];r:_@`rE7וuP=nrL]PC&y|Rabr @YRQRv$c" Z2@$v1C9M'"D*cg|8JίрvLVK)UňX nPpu /TxSb<b>RI@ "sfQJx & J|YH'] G7HfD_@m!#NwaN\5_qjRrmljeր_qʵ1Ro@ ҼEt-Î5;17>\dp4EkAӎ[ ގϱvw%.$Z gYHĈ DK sG$R(S:'tEJJ؉5NJSx& }~wK0g|+@:۰k\Os'ouxR\5w$03_IV[{u;< Wg~x"C');fS7-()rk5}@olEcPJ=}&SLl8n\ֆ]Cۋm-D3㌩[8/MzIm=z^7 w+SMw;e p8bӎ_-Nj*67!CY-h#=bbQ΢=pgz#Ή s؟ CRphdz ׾k!#c-J8sY4f+H$qf.=M'$;v VҝkP:/s8%q~\Dq)S @.e&|0`.*h(6,{!ӌ/@JC`̶rMϬc2JKPrΑ硩R"a>Q!Z*"њ6MQȍ ;1eswB[٩DN8 kҝMsOeoCs؜PwTuD6e>B!e'n_iooxu߼)"N=b[]Kړv= b%s]d/^5JdL.A4$r_=S'o$-X=ؽ2r NfsaНM-a:J WlukKOZKSWrt\EE3>yqԿs\RW^J.'wv$K~,4E2.R0"hÌݴ wBT#Kyl /jަ HYӤu2=14k۩㊳-'z[Jf>9krۑjº8 Vt:Gu&Mo":63u}ܢs|խqn$_5{#kʊ)7F2XibP,D5!Е/K/3_۶Dߔ 3jokpC"u 궔9{WJ=KM|;'PPRSҶM!=8,4Ln uNra"|@a:sߛ= h-Q68 *o=nlM 7RkxcP@6 VnQTjA(|}CKO(ӆ5HC~|6ƓW=0T.M4ԈRS̸Vd/>Gc@)g+#貢Ξ.zmO5bҦM9#1ltx9q[9w!~9_qǞ2Czlp7Y^'qQPF]'>|ёa^n5URݝϟd wi/&&+fek;fX$ؕdJx b I#u>iק ?@:Z ZoO/2Cvf1^HYBPmbp8ƨoy@㬭؝+ѣd`z(/rxEy*Vb&nV[@H4A@J:Eat^ fˣ<[; P(i6HGg|h䫽ofėsjY$GNcvLw'#QF hlj+lLVTw쏟;Wk8cꖟ]P* 9l\'5ۻ ZJ?®#?.1k(_eiSJ)CkJw.|;[z} Ow޶eG3D.{~rw]OK7x﫧5jWra)y(! 3|R6Chi/vfO,ޫt$3|Ʈ?Ϳ (Rܨ7.X=r( C.Y:Tm/|ѡǍI_L W W`_cV=zAs캂HkLT` xKi\ɇ$*[=DӖ$k梖QJzjXSd-Jɞ+d"N{ $l+CyeA J\h8θ]AA4c a$*%e\a%cI YZAe=|')!,Yhi.^% b( Ұ+*xEe$F:2Z`;9&7&!ZBPyWaZTSj8Ngt:ӪX+aK*u@y)H!b  InͽZ߽pwc=k;L,4"<he CuУCGdcК^E #c cR݅KjYp5S6y =x%Tڕ~[ٌ޲QͯǮ @OmmO,ӳowE9"泿Wߟ?4}hl(9kW?wEhYΕIZZB|NnEPle9=;k߲[:GN\5q]ŦXy"!~5uM[1\:iKz#[vtl!I_Xџ~`?\a"z|ӳcyŎGY3JXΡNW-938Dit.Zٕ|Gzm;.3 ײdl1;=mĢzkAuH'DhE{T3a)#DG>ԛ}3% {KYVS<Ɏİj!Pl/{A~| `bcg;j]XbuAA Zg""-r@R`2BK2uT(OeЙ 'j 4(!Ya HtKOۄ@{(}i+#%\"Vox[҈"Ooh]2B5[!9~j t׻gh^L,s4= UD2d$S:ʘDiա]q?<_h] 7oٹon|)ѳ'~=(k: z}pՅl:酃я~Etgf+'س\PL^a>6<%sþKGɿ^QB0&q>onG6|{Ε\v>fž?tKֹmzUE=:lif^ڧ^s7{g_߸ajzP5L!q j,0F*<^w b}g~ 2֒1clfG8P,]&ݐMO[?xK@BdL[a+ty'`m4a$ 0E)ΰkDQC{+Wu}Yn,l2Iuhi$6x4؉TE  H0QUM.#,AlAcWe+]H@$gمGyڸ?g,_xNykηq&bȈ(ʥ֮~'KQstCc*߲;}[W~ַljډd^vfpyB:$ߴK?۶Ywu}Qlؽ+|5rŶK1Z !X(k$e! "]-ʫ&:Q `.ugQLm1B^σ(#8(WOVFODzE)U])Il;bT29^!C[u |_ԬBĂg66R bs^٫/zU]Qjy}ܭ-5ر pgV9TǼ&cTCJtz2NTt[CPkZ) w[Z)H0 ^ Gi+;. ЙsթU~ ϱ|=777OώrͮwM.9a)V_4X:rbj%_-;W!'+&Yo3ʷX Ѻۿq,͇N =eW| ޼"]wi7ܟwb{HKVL=*{Z?ΐwV,=83;H;BvOYo}o<%csw|泤z=(WO[ڑ˦Y:.yWݳ4է,熽yUw0ޔ`BZ<< M5)"4N:]p[^ʁtx@qp?4 5U@[QpW(na]ڶ!na{e4iR4N:!)R/ftaM޾1gbm XHL-b(uMTٌjw5,dS #ҀF73(1CS)~Dyj1gVnKA0;"wLAf`([մ946Lx$̃$郅0"N$Ζ;nQyZ,B6{}ePyOg nUw<шMb|cWmӳG^Wog֨HHVNLƹwny ecw.hئ=0 ~ԗo_?S վ_J=^/*[ƁMPkcoAg f` Naҏ 9JsTS2L\HQh<JNx.jJCSU #:A'DYGQnk& VNYEn'XIK|o:3$+ZږYB@bB.L= !32llu#}Yi@l[?1I6jd-d{N!a@]IT*k1F"k+t*Ţt> ?RIqEH t ƵSF)T .`..25RƐd6Tŭ!QDƫ *_*ks!P 04:xXEшBr?|fp@Nl1(\MDe$VE5SxGEɛp|Y%8׭t#4}_+ _Gu.DOq\ :D"k,HD dIF/P]8tz=YK³A˨<ͬлJM`HcDIѤy0q€YLGH| !#5ˁ ^r M*j(X=0Lc#??isܩ!9XF лd5Q+>ʪ%lYtvFM@ԧHNm -4t\[p.ZiKRR.z<Cu|E2K98ac{f!)u yvq&(X̕s\1z Cs˫Y'%? 74 _ꁰ\hqȘvH:e:9lf*^9i*$}VWb" z4= ]Vkzd2ٲ,Ojf0V!ff:({t:Rc:Wg"9*cR.m+ !b7(n^.⦞zBgrom!qV֭L8bh\q̃@0xYmwi-5ZHe@pVE&4+e si+ꌉh)GO딂bȒ(U۰:4@$7WsszRL(lnX%9T[ؕ[5RrCy$٘X16 iQˆ\!mžYas|2؅LH{ږclH#PL Rc*4c੺FX_ ʳfpQiQ)5|K61@`ZW{ i40j4\ Ҙ-|r +feP¤O"=~H^nfa)ݨ 0>F*-}'`=_zȊRS){j]L4P;޷)Z,)H{*f@K^ane~:G< SlΫF<\3ւN[Ud>9얬0"y2Fl;F-s㹿904c/%Gń l)Nbzq"8CPcvc5Y&ߦIENDB`dtkcore-5.7.12/docs/src/dconfigfile_example2.jpg000066400000000000000000005764351476226660600215730ustar00rootroot00000000000000PNG  IHDRt3( pHYs+ IDATx̽w]U7}z^rkz%@ "Mm,(2(*8gƮ bDZb"!i7rOyثҫBtcǘq c`=ou٪Oc(1L`"dZנ :xĀ5< 40N\@̫N<0`O; ]ErV )KNhoŘQ̀ :uaDȕF4K$בCDW2ĕ'4#Y`OE&U? iWuA!27!~{̓kq*ʙD`4v/_9\a6Mb4|K{"r,slrʀB$ԢAE"R 07KĎ_ޖyG0O}ݹfJ&%dXp-rL>"d<8JڍNcO *-"gjF,/ FF,«`TtԢոS ).v.jKዑɴn&vjR4.Pq)I ̥0}3 4"CtҿERpŘItRUY=dG4\-AV) ffx7 e\.75+;K#FOy݅cYA4&h rԨ(C\$ hZ\N[M4 ҄i B ƞoB:10OWH! b@ "K"if_s;Ys}=$$7@7$]tV"U`=;/n +Ia|uf+ EaJ(K dJ*BHaHmX*!bA9iKJ"m|Tг*y0UMl"Tbx-% xVScn%~ʠ#L%Z=*F:Kⓧ{&I5YL[x h>uHlC =i2%)ʊ鸱D猴=hkAY&3!)YAw6^TeN&Ĕb,p=VV"x<"2!{ J]K$f$ "Tj $iUB l74Ta`ͭn7@bȔCzLθA7"""`@*VYAy(NU%t̤%Ml]OR'~B[Mퟋ~L9FL܄(((Z/8]WGmcP@s`B͘DO,s:Nغ 'Ãm.eo0z c 2(~QHWV!wwƫ׭ڥыmG*8rjq1X|ٙĂ_i̥˥YcF߹dڥ蝯ꁒ1@\\eLz 'K!!oTck޹3̐h?5Z9#޻k:?) &mYL,CGz׮]9~Ng.rfjVW_ug?n@6vÓs倠]aBVM]ԓԺO.TJPD)[ RQ(\Y O@V\~5@'*k %,5_ZA=; +82Z2EYd BieYg=2SýT:zOӵ@o?,h9[]}eM_j*!yq%-)X^QQ̅rxpy&gSy7LK-c bpoqV#Y'ty四h"H==KJG`  9e 3s$ɔ'Qis ʍڢT11S 1ѧIidG7Ws%-ݸ~+_ҟ*{iX!>[bx.ÙH8-j(5 wR>PuaI:)L8SH8jyg'?*Ԙ!=ÍlT!]cJhe_,ʩ&Ȥem▣[ڿ  @°wJ7$dsk+cw.w.66\8JؐncHAJ%2"+Otƪ[rGsʙC_5e2̙/QA~Vyh>2Zd?ƜO?y|x"h!1!@C+ `+\:?>3rlGz4sۆɰugw$N|xX!rҾKړ\J*00Q }wo˦{<ܳsR-ӕITo8S % ן6vf|t )joE}h-W D~si↲k_˦{l5i9D=ӥ|7wZ5Vׇ~B,w,~܂DuX{[r۶>>x~&3\kϵ?<ܐ ׭8# 꺵׭+ȗ7/#uýjUߢTZ9sl9hԮ^9qQb#ML;bɋ;\6 2NEy-^TNk_Sm/UVn޹突vG,ʅ3oNT_GSh(E%֪b..LoX;y~3}`G߮iE3uū3ObKAviī{f_z@6lȿe4kxZNJ!2N}{vG;^@LH?f̶\5pƚ>{MT X8^ yC-6DyiEqN}֛]`QCZx}`{ ȵ'k!njC 8o^8sFRh(̌W.zm}8=3gX1Yy]oY8Qr,uہ։RڕDf¿>'"Aeij3+MwjƾlׁΚyD,E3oZ8K(t͞լe6(,^~Ů+,9|_;;v|Պ-m`Էص޵Gg XYa }~W-|w0;<ջW$"'jZNA}f8Pתc.q-ۺ`F\Fj:|hk/djv/`Ÿ3[X~꩞M;.˞Y>4卥O;<7D/N*T;LCeX# Ö7Kչk79rzk!_ ׬7L$Bvf}ivD@71rF|(޼d!dl [93R๙X:RxD!l|E>z>Dȹ?;[<0 9]_>[ 3V:ƮX< jqc}&{We>tjV"u8,fGFÖ7KRc !d "(E2Y TeBK[*-IŌ5O 0|m ;;ipbKS7 ̴G?m֮L9pjK%RU+KO&ž̆“q->m{3堔)c&IAB5 mhhY>]nqn|h߶hj=ŧ :CvyVMI$P+G )$sgiŹZږu}rK-L8;տ,"P{*ň+`\0YKnq|"*ϗB3x :7| /{r3vA{Cl|X3MĮ9j@۶cUd}Dxxϯmk< /X}0-P爇9k茎cP&S`W{*%)Uſ7 RH[a dKfA㩛vtk`ͥWr윌i.[̯i.U@wv},=bcOl[8с;5˝n8 3_4S!`MKyUc9S ~`[ϮomZ qmKqusԱ\%~Usqus1W[ʦw; :`v$j aD槺eaa`UsqUc%S #=& >w((ɻzYp,vM,d]AozPce![T|UO6W ~]ͅ۶ߺ \Ey`zŪ}cN[9qzZ~uI6hsilus?=һs*~zkZa{H~vgw!vԣxf[gIVF J;f-K؊Rsa?|5t_;s=})RsG-֬O\xrI|cKR!WLu4m^ [,[ӉAL(Bv ˅|f SjHW#ްA}urci! 2݉jp Խ&UDnYv,\Η"P%_0-X!J5Xic(l> qw>O`sͥa>"֡uUDLcwߕ*r,˧<,nޛ ծ\6{q_6Єך+f^ڗt,]%)L'Y coVCvtad%F^Da0: ZkF S@̲@SLj} OTneFءl"ÅP„Z]jr QqltLNÃp%sI` vjѠsx6v(gX0h᥽YtXɰӛ֐"]1p@\scJPaT{^x IDATfXBApa$hs_̆craI6nj/\ڛڕx$ Yugt~vOΊCшȀm̿ĪRr\Z&`0UJ?tͼ3^m ىscϒmB6 ;T{*Gs8;0Gxŵ Bq_ 3`.t,^\KV0W &:8k*tǪpvMl |P,]Z4a81>>^*@"ī5dAtlx%d"/f0sk6{31TXh ۡ+= ^-=Zs{8#y"^&R}YlKAyd[f^=RTuUdn9F[60㛛 L5%wg޷bTVXn>hJH.&KBhMsiA7nl|Jm  ZyM]}u⩦+>c}@bzΥ΅Xjbc9hs|yMHoܢr5sd[2 &#^VV`G2Z~! 7qp&q|/>iTIT6wf'b 7!,f :cn=GEtTm3liEW,l =/n-Vdkdz6!cr=}NḾHecuzIm+bes原jv9on%fˁF+U֟|fpSȾ}odsgi4Dȶ,T.VדX1홋֟Ns28UlPrmK-޶,Kns<,htpS ;&ӆ akSr7^ܞ;>=b 6xC 0_|YܿQl (0)Kn6mOvMjo9ZtwFUfK`[#fO{Eٞ٨B:dC%S֏4\?L: Ht,N8s#װ@~v ] :g?Z4r١}ju{nbD$>TlQg*W=92?,jd'$ɵTmC.z%לLΉm?1Uɣg4D˯XuwOU&1YLg0PSs Bb6 Z&L19 G<1:StB%ηj r~)-Z\m _ٛ7Yfs*KV+П4T5X6"# fI'RM*ؓv'@fvXo;bc`z20 Qop:`1\P)5ZZUxݱE*$j W,ȉ,$ 5^ ,|eO.@7Y)DeI )A"R$8_EӞ'/ UI ,HgJoi{=K~YCe]Hߊ^+~檇0x)¿8tlHJqS={{Tc]>"U`ÅT9!|t,m,mlP<ѿWn߯mD)TPJ\%'U֛,n@:kֱ|حk*@oҟm64\~=Ll狋\a[;ڟSj@i*٬'YUpAB5^ ,<+( I| >Dorͷ3sxE UWxfhH>S82*<:@`6ZXql_k~fo\Xf8\mcmc2uGA|~6{%`3Uc( )bk)bOmw_H)9axtahöц٨tøJV]1M# D>li㇋Y2f ũrU`kD466#S_yгaYa8%"-sO,l[2n +7MȒˮq[N\$`EgcmY:jZ'z Ej[v_la%ٳT 8H5M]#a.Tva_n6 Ǘ8߲`jD,U]G; d(Lo}w_.[{gҥH=3͕:q$ t.ˮh.mh-ZKl;g0w*o6rz[NDRhP ħµrCI|0cibP.26Ek6HS[#Pb-Mx!Xatt\­[OF6tȾ77Q >ܙ~s4Ow=4|79o&{|_f{oIs'0`Fj;J˚J8:j+: b[MV5Ul}` w+gK}d.D6ήbbZd[$6 xS'Z<<õ d/ͅ %o~b7>`%CK˚J8BS]0Lۦ=9:k" ^IVBNOߺ@α>D׍&No˷Ǫ?c1ۋ˚J?{;V,zf"e}~wh1)mSCً41t%׭o\Г; =<'ܸa%j vN$toj;>i䝹ǑLkv)+/fEsKE=Fa?:|f+PO6Co]42]MTJR*+ĥh移_;9HGOkpi4ko+dFC_|s7sfT)CR^3''_ә7tP.g_708YDhc~cFZKӥƾL5g>q)ְͅ.. 7:h}T)fNss%ِKO3~h$>'ʮܱ|xhw/~|[}sg5>G򡏭 jhM[Ml4 @@8<\ uьj5VCug.+Th@뺦W-<5ݱox~"'a/X=יX[\B5qe|%9n^HQob~ cY޷Tыs??WY4<+6>ֳv/n:ίwޓĉѶarɟTsp&&98y9[7S #ݼu@Օw4_iQ"'HV4T:@O(9Y cbܕ9Cdя\FU_w)Anx+P l~w"EB9>Y Ж*뽤eXOx}DrU֐͝o*ֻ?AuIxIB?ܐ=Ɗda00`O42oXmgrPɶ[|T5U9$-]C/KAF ~|E h =_DŽa{IoZmt)Tl(|%ۺ#j-oxi4+ӭ〦pbbV0ż@/W^ik-ݲyplEEzH̻JXUWg!ܸ3h'xh-{ա7B ?۾8W"Y.$޳ĝ {䯒A Ŧ*_Q^X-K 7fEJ,"r$XGV7'ANVD>. Ŷ[qw;ZDCo^T,Aw/'Nt_I8`Ԍ^@EEdQg sA)SC0$Gm֣Iݧdi A ـӠ cX2xӇV 0X-|`$54? rY Ek}KD<^E!\4{`U(ɍԴu)ě_{,Ս~ QX5OPg\?xKGbY%]7хqy;C5)A݊ CֳVG:nN\] d$ 0Rgd[ [#Q+keOA2)uhApXڿlyp@E)p1QԵB } ;D4f!ٕi%l崑tiQSx+QE`Ƚ;^h8fYphiOVWSxMu`ꎃx ʩԇbbOO3w@rf[OM$Lqd;c_ ܽcPӗ(ac4j&<Tkd#VW|O7UMS4# ٨Fp/0<8Wmf@Wك̚i2^MЅ:e%PSxx{?6 n]g8=)C(cMIյ }Cn(3Qcxp*eҫrVO;n1'NzO. UL*Չ\TrYx9}qD}14&`[֔JJ5zx'2ؤã][93" vC2|xɇN#;WoM:7e!-7a0كP$a?NS>Pr"@R_,!j.Aú(ɍX>^I@*|{($'T=u9Oث#oޮ^0x˽Ebo1'_0|PC2})/`4#q^b /O`~ĘM%{El %S p)훟Of@Ļ珀*[Y(@^𢛡:xSj}op2 R$jdʘst@r&-6&H tk /`&ሥJpS=g5cԇW|hݸ jI5"$^3q"FbP̈́GPR&eTud1&J7/۳gU ,P)[3a%7I[L$|&nׇ@CGwWs&,K@Ip+*.*xZ, ":.sq >M:~PV D@yA A*߻go9k FHbTR``KBe rD DZ>x|7]`㮗 2k<>1T'_/ hPI,!Pb`f]R7 2j@#(VԐ/F'z`LJd4MI.RFE[#<AL L-saY=u#61AҀ o3}#M STSЦ.GׄY?Rj)4uAw9_H6PG.)+ӪxLA[@B6kw|fz'҇ 7ab1Ykt5a"!H%#ȀYr#SN(NϪD5! P؁m Kţv[:ϙ7ARi^4@ZTH{2@K ,A(_񌩱RˬV 6#{5)'z:Z92Srt|CQVK*-E0N=|$յЍCE Đ:3@;кSMPr*\Qj @d9U4 9Q3`Y/΀kBVH9'N 3 M@4T}O]l_㧗x}}3g/9v/<1r&8H3W=ْRK鬌 |DfV{I0ԶhHaJ @wYSP, }XBv)'wDWmi@xCodWf]'gb ߓ(*U#@ɓV$\oiOsӯ7~ pwnG|ϬB9y2X;77#gΉgV[Ss?,xa!uɛz2_y>o.:*N1"\_rCv7v,Xr5 xsh/_@[JIEUGz` ^ #p0+7i9w_424bHHkٙqAs+PےAJU⟤̱!,a451_ jPujV]'Azh">V^iK Z)ؐusNPprU*2,_8IDyP3*5\#ȓU_~QN#ILX݃P^3|]n[`նr웉[JRO@Iq+j3t|*Sį8m⚞˂p¶L1::"DCsLoټOŎ0iÛ>x#{8?:za+W?`1ڽ[t'q v`^\tJψ;Og̞&x~dsjJ]<_-F3=CoHf} [6~zt`<7]{#?KW0 |xbΥgx!SM>}nł6WӃ>vl#_`2V3u`03rP)\U&J\i =āVeE<Ϻ@+U>1 1/ԕIWU̺;Wd8P*lW֥cCE^F1$"caqP.V//&WIg7B\3MTMjYuNf,ޒn4G:v/vh 6Ll. B㮖M<f9An@gku#4jv217>.3L3`\bHe.HN{/>]mBj>*,gQщlܛ4%/\Bkj"__aB3]{Pn\}cp$B5G gW?tewZ-hI 2 r5+Jʖ63IzcT(`fMKCq<^AŜb5FY|Gx}玿m[zm^XNr`upwFՎt~kX_&EFt x (:=40z*\'RhqDYX1EJ&*|P9HLI~U< ՞ AL@%ưT1J_5fO;Wth*GJ~*G0dIEԆOpjLi)!ĽzakӬQZ]DU Gt?oX9@,Y`rXWs, ӗsLoF~ Ih"*M$}t_> 5`A'`5익&pܟ?STO]̵?}vDZ>?7:^-C_ྥlmaG*8# Z%ۚo7܎h}nkȹ]lAmUmcɔ5%@i u S>w)g㰉lЏgځo߿OMOn^72F+ꊠV3ؑ2by0;e_0jם]J99 6X`hOII<$*W}Atx'%".e,Wb5K7 i[ gZh`@]4 ZymA:k^@7EY7)$h 3K-IgrW-9D%fb(r\)ZKYKuH您/+֑HZjsGmU1%XD+! +I҃$fGo`N&f[Y T!O75KbڱnωN۶Bi*-Xزyw/5X&:=I 4FRLβ~rK:޹Iװbqɐ"8:ZA [v`:`Rf򱱹T_0=48i{ݮNΜs LI CbJ@mVī8pi\yJ A!yC0!$9C|N_Z}7;{ UW{;|1ėT R`Yq/~Q&{o=zb|s|ywBMs5\;rrqq"JW"^vĻq-\tFKDT2$$}1B3=)g܉(On{tn B!%inUٶ^6R5Wvc:Wp )-;N@ſr2"k`Z >@0?Ud[|Pz xGT)$m8DاY̜ڴI/$mKhc8d3a͖ۮzeKG^qYvz9}K8+C{g~#}ɹwrE:o};m=O|^_ϾmW= ڽsۡMRF?7^KOgy؎oImGsO+> WOS.":v|ݞHFF "Ϝy/~XneiinieVMog__{?sv}c'}v [n?c;!L`1]zϾ+眶]z[6sh 1:}{܋䟯zv拟|ᢻ7޻lyOKz}ߤ#oyG-=/̖ KYn۽m7^BS/=J> />}Gn}iw'?u/6'#Pu-b"z}Y~w>2{byq>1ڼ83];?yֽ;?%WF[odebҜi<搨?ܳy;l^/ _~I?ٱ{| ^3jͳ7t"\T}^!p%(T$c), 宀+X7>YGM1EdmgԶ)I[vlքӓ^get⮑E()X*ڳ11HJmNGQfҞ+4 lHq l4ٓ Ӊs3W|+2?vx׭γo/۴=vڽL^JFsw1PR/) ?k>&h8ʕaڲq/|^K!sdHy//} ~ۢA)8)6W%[q/Jj6N8IC}݈Y1@t $U ںq놡Y.q af=j ̷>[Ft+'Q׫&w?chS4䇺6r:bؤޜ5%"JV%E.hH59Q!  uZ6>IYPe H !.y8؁[ C` ʭ%9I,fH:bqj%6N|ҫp}F =:r,PAãEj($Op襛@\c:rH"s&>e˱W>G}+>Gԇj ( A箖!EG{qsw25 wKbpli"5\W åQK4̷C _A]m2'A)-p.UME4Qj;ټKIxmgeP iZ-Ö|K 1!9{ư p.Ydž{H`v4 $68 ΞM9a AOF`Y#PVlk-pWAyPVyFU^2yޤGCU.7fA(sJΣ 3Ғv$pLwm] y`.e25yn]v$6^J:)ҊqL Nn]]S729"AL: 7"GR(k"hئK`( 2غR,@hkqáʐ9o!ncM |ټ`u'"V/r>G(t8VH@lI`C: 2:s4!-mG o)f?ڥbi vs⬉9%dwr㜸Dnȍ539 7_;VU&3oЭ0^ˀReы@5tơ qzPlb Ew=M/垧m$F4rAY>'n> +hf5RGq>st^QxwC/'.qlc8P3S'[&&Ւ%" gqD!%ub,w/Ƈ9ADYfX;Gw>VNytvgZeU-[P>> .$%wH\d9tmpKLm'ӷjXリ>KO0su PVK 4_3,i wbd!#x=Ѝ {M@q^Ł=\ma 0XrnjK#(Trll桴@MmNgy$pGoO K @ "*LeS]xɤ;^x~0hؤT?|FoYWUQX|%j_L7a]0L0赅Gj G )!s}A?|!+7-X! h/G}(f)CR4 A#B%iZthBܵtP:!3]kj$EBcO.=X_!Gnh XP YA,#L_bڃ 8.~q &_2KakxVa#씺dSR_#XcmьHkFWg?֫=wEU)'&_uQ64:8#$1'A/FZ8Z \_.3=TaDykx.F: d[+˄N;20mb@b̒,wne.Ktl,௥0(A2|I;@0!P(]`qfپU|0h> EFNU4vVc9b )\*z`b9$HjA'QH+bpeMAusvWPI߬$Րp!"0tcr7}୮]rL)j8:8AOĿ]ܢhz G2A5#2\мDEU}z} CI*oXbTZ`x<pEo\Y#OmdG/&)%#x\ go14Kh92_bvNsQSbE ~k@$ CF_ FJ˙$@cPBX}/~4x[$BwvҥgDup9w!aN[~qGV0'ĀpyFbEO7eFP$ 7SXHMoyIf^ * keAs=3 |5+7RCr?z$w> 4Q,ȿ+ξ2gh!5S2Gp8v`|[Gj!ϗGg2`s]Zq 3'7%qARtʍHt[6ZQV-3]`>$ N2ȄO[8s e"u1D."}V1Ry f~wD}s Fqm 7NPkAƍ ApqirQx+ B.ZN+#s $NdIMhys-*So%ďE0^ru2=yWj-+ƧV6ФƷ>9 S=:,t#מqWoݳ@w"9\q TK& :>nJ9ҁ"E >u. z6Į!)mFoB(|ƿK2w-yDu26=f8BI+\8 X v7kWVhH%g[YuEeIÄGP3 5HZdw9;0-XP!9 yY5lxǂ#?HGٶ)U*F³ f xCjE'23Lt`"vQKq~V]m@p8U l.|Sz=AMz!T_w:VRj2Xd4fKd}?oyy>~m"vy HWT;tNS[ +huy&mYR^U ν:tJQ1^+ksrƭVԷ v1ڔrh%¥pH\*b}G[6!:p\*-r1MD4D }NEe)!"@W4`F[8]~-5/pJ옩 Wh>[=m7^rҦܣdEw؛(dt,ǗbMo8> &qȢԻmq#>D=Ŧ䧾-K< A.X(L^Ѩ4"~z# FJ9`XwbZigMKV 7Id }>VCџE ߍ B-u$q ~42%uĢ/@i1/+F2ΖHH?T%CDːdW/ρg体I\2NFk#5z'/u b,|,tqzd=$PTΡcaN37+",wGʬv]|/^g0JˣdNnq&f]cdDeW˄ǗVLv!f3 xois؞Nc)!&ˢώ>6[ys; T6k2u1^RG _M"D <(&lonx]u1 Mgm!ډ-C+GCsY {ļR_6O8ShtG!w0,'L8iz,f\MqAy\2b[2+Ȯ:"uի5}($dR%W^ +4WOѭY! NU4aԓBzul K:d"t(_f(Xhr=-(L9&?QNXD&,dIdΠ==LDۂ@6`52: 7+ 5‹(lp1a0 ͳAs9x[;6(:Pޔ` Bh| ڠ7X- S!bXqM:pev@j+++L O 4>89z+i'\ 7GP$PQ`jKp=3_m!Y">iB(4:bFDj!x~JS?QAgotc&#r$#fL)euL|z!A3gG6|>LD7S88"ʄ  $x,֕R3uYs1,ALe0=&YV ybuM9몇c.!.uR_P^o+x4z,c1kh&! E-SAi&X94%+2٤EdIkbaawO"HPEԌY8 #OķV^5Λ9.Pҍ @O:!A b:查0;ȑ!(Ji(>.%LQ+hA\3 쭃ؠ1Q,$[^̈,#|t_Y 64w+oz%_yy|0҂nJԒΙU]eCKE`&aѮ4b} B}`D(%: J]f)sWIBݲ 4bm#}YHlv&NؙzTnAaήBi(LE؛4G=ÐST 0`sSX7ƾ$hijui>, _F>QWlQFjUPLkM<^f<>9?Вb`hKI1;7$<,Ioݗ~RѷDuQ%#"gE$<[!f:io3FF^D;Z)@v:zoԘ[ ku/9 &j/OH a>ILBvH2֒f}_vb'2l?ƨ%8&] cSD* tG?GSِ|UEexM)d(IQEM'{Ň;h-%\)NNѨ;gԠp pӘyx=_aFX%@3  32d#p" EY6⌀ DcF45 ʢ ؓu;~ѧ@"8(a{zz1~Uǽ$P詬U< -W8}d Be)*c^c1:GSss4_N7zZY<+3g5֌60S:b*$rU EP:h{azANԭwJTnb;0QE~ilM V`pq)i:lHe:oa(yF)(T1&A˦yXeiGK|wDlcL#80:L]Xĸ2SW`-m^$ B9S5f1!rdS."|lc\RbՏSL~ǫĈ 5QEү>[ԟ IDAT}u'h]k[b½a聗 =F ?%S %EZ^+0`E %t;&/ʖP+}W\UhT=~hdd%,hCņ&<>eUzڹPs3%SdYBz#]ScXs"fi0~ƔNП X-jW%*uA0>զюG>w3Mhͩb8T)X&:W>0cW 7"2i1SC=VUTB,00hX`5%'>QZ>Lm|+ȆtO\0`.\i -j6uM sVTS_d|*'Ycs!Aʏvd.<);aKaD%Mm`繣240pջ&W9 Ýƈ.p|rv2'9VH׻Q8~1IY6¼X@~u\syo=DŽ+5U 50MW9! J \O싼0& )Ztg? yx[@45y1aCl/ H\) qb]MDX{QPaH48r 2.䚜 +=tj4h sRx^Wk(71H#1BDhs!Δ2椦MP 1RɲtI)폞H#i C8$ Tw,5Ϯ8PiMINIa-B>lq104EDQԒp j9 N@2wٗ!uc{ve'FSfh4#Z'8UXH1;OSi\6t"uTUOO7X1Su-/Ϊ}1e fpu 2 wgd"3hr}ⰺT62?7kvn;^k܆٘?{V{ / 6,_z/\1tC=TЦ'rJT8?7 g|_y<Se7 ʫ GÂVq7"e{n$ƏH+dܲL: &[58wppK,#7bCl.T^Y!ZiK9I`ȣ~k~!);M!?G*ʌkFv3?)ep=̮5/4%ouA31~ X\\Xm{7!bYS|[8j/|fH$}~NVk}B? >G7_^:pt[ϹWve~?+ʅDi{tO^7,%o-LOx|eN7uwv{[ ɋxǿݷ>봓ok_9_gn?_~oc |_!;Oæ'=]^xCm ~D|؆]|]/{'⺧|lٰ|{wh,υaZ^^}:f3"&k|^p1Uji47>ztʜCQJTb#;,꾹xAPx}/' ]b'];V+lwFsj Fn$Ns'p̖.,1|'>Spzm)&v> ?+8*B~Xcߎ佷FʨCi-"qJe-3Ĥ2$>1Ehq=@~Xq\2`8b,hں%0\׼:.ӮYb`3BJ'p-tyD/skg.޷'|n?_|4||Ў~ϽKBD_E++|mO7n:IJ$++rϽ'KH^'O|?vhߑͭңWVfv͏}M?ۈHwrSl&DNkv!ݧ#7rލGD\v_?/Bo-Ug4g|R}ua0ӔuhyZK kJӼhv>r1C1v.}[Ȉ)lxZa+`R%>^`<>3: pK.@l@LBio%BLD_CBX(4ޒmC{˴LPW܎עQ m]\M0%D. ˛ hqT?Bg.opKeP,ZC7FdtVV&%]4ʙ."R#ΉB#{E g،B"mZ+_O#[莽ۏ//.XC6Riێ<}~ʛZ7Km>f"}N̖f2J./xߗn5+KÑ0)$6:M̖O|ĭ"RCrӦљ@1 Jm,AL+BxڹbB0Dmw6ՙk("hc-$3wX׭(s_Lk eX]7QaZvT!y =2ǵ 9dFV_!,~T-t@pWxITr8dNEk};}C3 Uȷ--2t+" ĆF9gSJpxk]{6Dęw.Y.ѕ2IkFPǴ9iN,YwELp?x7+su`us"Y^YvA{fMDtb~t_?vo7=ND IQ(M'iIGۿ}o~Lh08u* X*""H 9wfyN c-ByٽM_:nb.ԛgPSVF-Yx)\ Mq: ()-8tLK)tW5 [NnZfWCJrNi ]̰1S0x@Yr|R(9 &(Ti4Vwu("b'`:(qIkzaKsh~WRԘȁLDQn}NwIGs |ϾGCvԃ9tmtCbڸb #DЖ|=w{߹g{w)skIx.aiJ=|+.v׆sFRE 6u_z?䑄4K|%Vƥ+'g>rI8]ݞp .ؖ 3}|-nSR)Y0m&<>9(ôC!8x͸KZf1BGY8C v_4*~+)ݙ2C𡑤Ќe}TLl02d1oS5U՚xvmyWkRH@Oh ݅7 H8B[f;W <|eվ\~h;De6l'Ƙ JfUJ40E;~{¹w>O}/9"}褿^||}ɇo詟.{dg_ϾmW= ޵sۡ.y_g\v?촽O{7~Ϯgt2߳oUOڅg:cۡ=tywˏ>~{Ȏ}w;7\Oʌ'tюgs>xl6g]}bG6_r3vO^B]\ ӎ/i ʺ K/ܳyÉ;l~n3^4aY/0b"lPD_\cqOR` !WRpշT4!{0X8iFx]Qm'g{T_gg8*&r L-–ojsF4(G r!S|P[n5w P@8u&ybG*wq]^Lڛ2! uǚGhHď' I7Q~erζ#>iD856 V=#f䎦# w#1b$ +cMiK,93op?8/𼦩g/Z%觘 ,}5~az0+NY2$-~X{L$m5M@±%GMoRin(Pk,9ÒD qU?8m]6I ;2\;[F]9~jSkt݁V¤m2ѡcpw[Zn|=8 sg')43k}@:^E(6$7|<7U{؉^xԳeЀ{aOmTEMUam6e:R&{+, /8Lm"# b2P0#]y|_@(xH bps9\2aI՝tURҘwJ?b>.O(cQeK:.T9 ťz([eTo3.y}K3Jx.z`9δ@88DvBؽݙ 29TECD|+vڵ`07͉ 8g#Q[!,ܝx?3~1:s?SuWsڶ#;IWnjdL*nد4 Ղ.H&rtꐀmW7h^Uy>DmAT\4&&m[C<ᐦ@/C mm-XR0zDF@<}U1 |DI0oOη:0)9&KɷH)dƵ.h}fHV4;B}T4̠k T {f"m耣oQ>jB!"V2 aٵ )v-6lBf[#L)5`pʝ\x~ 3HhpeJ\?q&ӄr!?tFu)5rF$EB(J7I vݴ1QVn[Ȋ:\CI -A6i U`-̤'nK^a(t#pdP#9̙c(L`ZB1 V]+>S )` IDATOh/R5hƙSk+W(߮Āb,&W;tdCMMŊ 6ʞ*Yd֓2 :4QʮtVD@&h(vYSspk@d!N7Mwq*V8,v Vz+W]ɸ3Scus/&$Gzߎ =54^=nu +3NT5ktK %fݱ 1lЊ%K|_fN!>5H ERP_dvU S(UtGDY}nun[b}Jp"{Б BО(JN2O [>.Ae]ynED2q&k26j3<͒7¾=min"̵ Hl6x"g!3"x>H$>䋲+1yǃ)yR $[NT[J"PR^?@` =t3ŜsJԷ+]&m?6p)P? ʵNDB4kfÈ?}thf=M{E[gLc)U$]PC: |Y>h^ ]ȮwϘYfc:cAidF?n݈j kkMK(k?hm8% a= H.Vt% fͬ؈]Mz(އވUǮ0?147wO.ߧa>6hqF2*tTeE,8 '|X{LJ\[ + FS҇~aF倆eِa?Yܛq·Xrl$躋QeZArUcYr6mlh{`D#7aV1F|)ПTEf.PHL?_L0 (a\Fg5r|H0@ &ZÓ4;KN.Ej%qF/A42^7 MDP()>tHTx 3Zfνڗ=קo;LEb~ݓx`Fp>` ] ),kU3v=MptKl}G4V;|,?y-}{][^W}2:o9}˱|$_sm/I)/C<^M81Jo]o#xcL'7I`ȾSOk(T%0.}xwbFlE.qgXF1aԎeUDlum)0I;9Lx ^(;!8q'Q%sC/sn7 \jLcB}YJO.᲍6MT֘s>vki0 XtV:Rm,Im&ʺGxm [ Ӭ5"j/3"ⶭIzwe=++m4qGVfuó@ U.3شU%Dٵw5']g޶{7}Y|˿‰s#Ͼ[7}_I{3z+~7fˍw;^3kL$sيdMHfYN *J=ELv\"JU@fabUdGDXdNvc!vVlGTfaF|MKdhy2Xb'[9 3pf˪x`h.'Xd Ea\j8{"IOTdJldOScQ#eb#k+-CxϮŠ > c0+.k;0:e&Zd;®+;7rdzj@ϖo޵ald2X\.di銘gW$m |@12D|( 4rӷνHO\f<?SqCwND7rGD\u'~S.Ih&gp]oe:p%1*&Tw'F>'&I!'^>;MFͷk6@;&tHg`&JGGWWCj唛 b 1LQZ$V/z26:>auƿb7~'GD&T+z ip1D)r룸c nw.n 8}?MyyED}("RΣD*Y@c*Fj1Ы  p@2eL$zZI'۸ec'fK ; 0JԭG|wbә: /0nVbBf¨pPÕ5ɭK;-.{|RW܉#~¤S NuCzp-d +Ho< 2@7L.j&?#JRV3:\lx0Tu !9"W@M`"b40{)02wD ҍM9Ee;+2& $RG'܁%4@Wε E(B΄2WMc^/hS6T0bl \n &u z)mLx u"m[O^ZYKޱK{ƞMON}beiׁ,,?d4'4k?LJ/" p6*@g,"LJ(QcJhs޵<p]wFOEߺ) oݵ7\z߹,ZZB-|AUzŐK( 2 KVd}5RLjv2&XHm{|5G;:m\钙S9CA*e>#"oML~t]m`Pm]Jgh:?&=J*clDz [@ ^޳/ذlw#EԶF Q(\na>-(ފshԉ[["ڌ[dAmMO|2'2XR-.R%+6kO/h4dt}ZQ't֤8gOۀ 'oF;eCJ`:@d0knkAp_i$̓Huy;T {BѹkA-X+h2\$#F$|E$Y*x0ep&٤Om>aߵഹ/沟M7`$`j*Sj>zY^6Kͱi )}n!9U#I}V HGv4ޥ.4ɯ"#L&@̬-) "] Sl7/1;TLe2.1u/pHTpΓ@ⓛ_(P"׆JEu!hog:T 6zTFq2\ڒ"KQVqEOܗG}WVO\sdP!TF1#hiunۄ#g!ۗ0YOl/ t%st]"d2>hCxs>cڇ21B:1~1P\ЇR.0ml"N3':Ž5*ww'taI@b&@`EsMe*Wx]qy;@y 8H?A=Hɂb] ٔ eDZB,J4JTwQMLBrV]ƙB+ 䳽\ҘkJ8"D%Xv#^v[@0$2*\ bigEF<1$D&ZN5Ѯ#0 h'* ol^@YE$y/8,J'?L$Df$B}a@jJT#e'Yʇ}1J2PWtB#F;r@욼V2bS IDATaVTjvxiCv& އ=`FH9r"*OzotӀ .?&Y񉚍"YBOP p +{ۨb#|LT[_%*Ph A /%oGcyW,[ zOvFOU]bvt_Nr MIt@+<&lwШ>P&["Q^>|']ER(-Ld5b^$ ~=8vP6SJdlKah!dc a0%/qG4'schaǬF,&m0eg*1Xy!1HP+tSud rkKܵWYȕ!ꌢ|hf.OIk4+9DbJBDzqDA(eVLU' boHHduGp_|8gz'g3*?;qD@ 6;* d+#m8D(H:g.+rݴ^* S/R|c o/W`L<)~!!/V+;>Nqh2*A0^N\i4Kg[$<Ņ|{ BCUF!e亰ciL䟻 ^@yxHSA^3TyR =`ݕɷ˻e@ +x1dS,yTvdF3D$XAӕ#pxKhyED{PO%EE&g7Jx4PF*n C"KNUN9_ٞyt;"(FV4fQ$ qf{*R;MӶј Jn"QHoҔ!*终dk|ҧye,8?@ScTD$=Eqբs+O$Ԝ1L-@ʞ\,FBz#iԯu N<\D풕A1f, W1c$l!sP;v?:6ܢ]HDV3CQ^d1=e?H2ǐY8;}˕L'pQ֪%W%'Ԯ$ H0YV2ɳg7vS MF T  $*U_|`8 Njz zӔVowId@s(>fP^ȃ~Ȍ\;HO ,\2j(ct0*DQ 7 zrժ\Hl>~mFE&ù3NIcSµ~u;oaKt*a%4 =TtB_bZWLy* #Qp$UȽLf|fԡ?) _ixw#ÔcUrϭ0!}èD$v`VEu*YU3V3" 1K/rX{7QNȝd6GS1Oٱ(L!0|Y+F~ O$+7+>AjlS(=YdZs*MX=!Mɨ"2LOjI- ވU"H'S7CTn񯂈BDAP0z"/1:xCpϕQxgݟ(#}l:":6jRX2q%'zu!@ eo".K'JM_ii)+BzZgۑ/ѩ?J9Ip`c2QîQK͗NyO§ iE&l ٸO6"%3h{Bۓ kìsf[џ&'gY)PAԈWOi'PF%XsHPB|azt_&${Lg ÏiF@G';{ 5ӃpkʯmI BuiVaəKy0E<d1EpIN m+=wVX.7OXv. vCʅzc41-u18@eDyDCH>+:;!3d̶;͓DK~7 .-$($Ap:K#L&58ovj$T:W`ߗ2 ASftRG07`iFq-^YQ!C!;ptύW($pX#j@ ,k}Y(L (qf,ՄUldio 7Čs}+-dT^lk )`/WR(;wpo_7a|K,{=AfREcݼMLE 0@ʟFk=SkE㇟ͩs^{̿M#"ψ<2m34P)D567DÍi'\58:ݍ39PUaWn&΍L'ۉЦ@[lB,&6Vກ 匛\qjx;~\J+:t7ׁ8ȴTP sCdG:ܣ%qIG {lHAMHP*ڇe9ٴ<4dYhBс yV)8᫧?pЌU|k|Ąb!*ٌ99]ΔsM# Q9 6TfThK"F?2N{ZgΨ*fz=?*B%Gk,>K71r )h|7hs%79@U)4 Hhpa.x-̈> F!б;pU*>߱ymӖfPFw:7+F0ZwR_Y=%M;=Twnj<غiKƁ6YuA~Z#z7wnlھiKFfYZ5{P%'ټi^%8~? ӒUɝyqwzȷQ##9wf0ST0їG8'LCt"pDɈ})@RO6qJ#M3W(&0^y8"xȁy]'}냈"Q—P0o$U*Ȟ2T/$éaR] Al#9G M;3q7~u])d ttwaGO򘶡^ݽ{s93W}q֘wߋuܿxGqWLCmW~/9cjVk|rn on8:j7/=y{&\v/歋~kl u/^K+w_un<WLUf6T+SrOݾ_+7؎>Y^@S)-uwpt/@wn64\۸TS9g o%ӣ1B!!I 9a#o iS[JeGp1܍ "XFȶ<@g;B[僙>jl#Dʨ~{PfD?c\&F\yU@W8@HDeYNdLdW5*B DX`EI?pĺc?ywo? xQ/Ov~ק?7- b=?~Ov=4R־c/k=W^x#`V^v7O'=ttuƴm- _Y9n8(mQp UWZ֋N[}'=Χғ2i/ypY6oH@=~av!Kzi/q).{w*4|V+O;xYilm oqw+/ U2 8rsKuoyWG}-i6m)9ٻNwׇE}ߺ+/#p#3sh@ .Y6'o;񳇏; xnwm7=5Wߺώk_Y=>q}_qAn\F:s)eR9mQ7Ol۱$|e77LY#EI_xb&*'dtV*ːL+WML% iYq2YHX^S3#}2&z\Pnﲇ9#ŽK'JĽT5oD65d*e"} yw1ٕTpS6KB YwB`q% .1ZE$*',dn@p!o{s·_W8`5v{pD{/='?M6^N/@Fѳ}Z5k}|>xݣsƘBg-Y> @(tG$JδdnKkajW},5@"|+[|W'3^]3% N;x5q ӤO{o?m4}~exmLPo纾(ƭU@eMMyс^a<nxr΁3V>Jµ@o{,mwQq۽M>tQ?yqUqrս]c9Fz%_!e nͫ{fw:k_@cΝ!he7M+'0]Fđ^~j.7G\(5nOy7cp-0P"5 zzU30▝h39IYѵOnwɴdiOn:Q-zLj~\ۉ"+5ܐ@ LLpQl eԱ@*.@i';&[c|Il&{F%h?,V|܉`-\?M7m-ܳz]lj55\ QZFjZwheSb_tH wD@U0e[#YM7 d X{L[7v`Mexi+vho>~SO;=~HyՊ2-\zO{^xǶlO7/.|s:Wt!3gʿ9k;ggc>wթ]V}k}[ƴoi^%"A7v;w7vӺ6E(|s-IZ;>,T욣i&=To/"FvF@Kyɡ2Ī_ Tqvsp#\W,cGQ,gxNY4ALCM1"^ag *~oT.Ϊ "Lw8f$_xP6݀[jhfF4t n(FG\As gѬ I.R\ lL7Ak߷޿̥SYN$FZAhҀp)H^r8˒E 0{s^z{Dz,Zj'ZgM^}cBR`)u}cG?c$X7fh>kZO^4fM!Ơ/jid6A0V(#To8cr1[g֖vy9w[Gjk7blď% knڲBˢݦm(&=W1/aj{sޮS6z{ +'?\gVtfzoe@d5]3&oXke=WLX5RH~;şt֝O:ݛy1[eFpJ}/tׇ1~^?ܨ464 o5]3lXkeτ7Lx{T3O:BJ`iiXJF/+rݕk9Bٔ[#MOS ]Q[dP_ay $ swyd-1,ֵyL¾Ù2k՞;l򹻿 7ΟIijEvepY : Xi}^+Ǵ XiKg{ ڴ}/RZ"1mQ-zQk`}ҥc9G=RkD(d#{L0cRϢvΑϴ ׊s߽{=/}觏0aS6kj=_>#|3-C']$g>?Li?N8Zjzl%s?4KOxtigN^<B#x"(kG]RVZ@)B4تVvfJW̛첈X{5^[UzE2\Rod†LTt iɘH*B)8m *vfٕw)ޔD1 Or۟LtRp6-u td')r{s䬧X.?P }(!gԝڿBui<%uh%[6W- m}wwĜ_<:w)=w;{uݏeq3GZ+pdz/ݏ;XV"թ}+{&^𣏽XРmgևyCGϠja C*P+QX)o')0"S94;4sG̛7wg剏jEgw8`F ?yஓzvC~#e ,.XRxh;ZߨNy+'=g?k~c ojzf6 F:OUtxkÄo}unE93W~ao>ݩ7?}Ɓ }c Ҋnx2I䮋]Kixʿot[{/9Θk0{n;{oh4[upY [׌_87O})7᠍-Xrт'/94 8pƔY1,uk/zEF9E=)ac yh=Vt.#9aF$o*5st@nsIKccwI\,ɑG!R:yv'bbTmٻ+d~6*DUÓϸ2aŖ(L4҆͏$:εl,UZs5΋=opa8'_ݟ>M:$ .qZGO/巧m' ݝW^tҕ;˭ Qcw0$ӄ)Ԛ&*e%&爐OU$JB7H8N}'W}0@}:ϭQSpX DHھuUEl5)>.Ct)l}P K?C^:ǟ\+d"T#Dw.VI2=)v;Nj,̧ҧM$`П16&Ϩ(i[f`D+%#ꋙn瑃CP(oM0(u(Na#ގWÃPKq~+ax},^[ lڇ(+D&.N]o86sY9%#5|+w`2A7QA,|I%BWh#l5Οʞ Ͻs,N͉#*S"*@ ԅ 'x I挆21XǓo4GHնiFZ>󏊝rNCBt@ ,hI #5idlz"J$;C&g1{'JքR}exp_ vFP8 xc~3@nooML-w9V@Q9h/ϭ5Ppetl+ 45+ڧѤ@HbBZ"%xNٙ'ʝ- yieax5C*ef' #Cb)͆[\ݧo&=>0h&}W $*Nj1ze.~[r!骢?vʕW [ e&CJ2#76I| 3_騎\15_>6h\0fȪ16C"O/'H D$`nrP$IqtX5!ߕ3a {YU\mmD (hv,SЌ.M\li A'-|ɇKG <ÿ!*׿16bҏݶX҈Y 򌧛YP! XsAԙ %" " 6: ՠXJ\]yN%%c6kϤJ١ ֤Yl)!,Ylt0嘼HgG`Lp@Ĵ%]*79"h'6-7O&`j{~gS%28{w}kXk dc@AJPEYK[kw&ba{9gL㭰2O%P޹7-%׼cԢ~ƙr,7wmDETcc=H9qh~b-ݥ7Y;eCAR`,@Q ?Ch\0aI#9t\Յ%Ju,-Ȍ",G"*Rͽ( )AjegQB#yVxШQ׾2<Űl#fmp[ 8l&p{Ab=7y^,T'MAN@ݳ[S ;r\KH BN惋3dq@ N3d/WmfUe8" aܬB\f!r՛⻾AL/tĐ"D$ du/ "Xt]r U,d9UG g;xGS2M(L $:n=9qg%k-Z1Ƚػ IheVEZ|-gĐEuq*% utnecXHay@4a,4 %+.D薌e $@S3IF([l>9'Ѵ91%XWb3Y_gp# vb%a+X &`e@izޛ3-"s~"pA+Tdפ[Z034egM֓ |".":2AJZ#w9qYru񌪜9Dܔ]DH0vxߣt}1"J=eUkq0=ƭ#&Tfԡ K^lhV.u _'w=J# bLR"WsLZxEFw ΐqtױUdk2.BEm:zI{iǘ꽻#?CIw jd&hQЃRZq$7f3l%i>Gjc2zOƸD1~'$V jrg\ϳX%bkϬd/_D<$Dҟj]h#F_H>$GBx>eQ{"tT0QT+?οC@Y:{w͗*ˆ0̝O#iPF}hMF${rocu) m1&<m͟bFz*H ϙDw{ B^Fl\RxG -tMv5٦ÞFڨ,îŢA&\d4B*!;X$#Yt5jHoלso]f7o-dhG:iB\0NPeźݛ;Wy%|gg^r: δkz.ek|7CR@fF]/{cib W=3B5p+U@ A;|=A6 i)U 2~8v]@+ҟ{: `֤N)d-s?5sJVO7/ZTy ھ-73oml1W->ogrl?߲Gԇz,K[N#Sz)Icnlmcu"ZѷmHm㖎N`?9W'ܾ :Z~pyz->^?-p lm)HȆKߖc]ȰH3W'~OS Wؚڤrl-x:h=JQ° eE@ϔ#iy@_$eM;_@J^qY6M0*Ԣ]$a(j6Fkyܼ!iPɨ"(V߉bʍzw8i!N7JNvA %ZHc A ?htEqt&ezv%IRLpLcuFL"0͟"!{Owv~RMl34 pAhM iֺcv *^Y9mɁW8x/K;[6ݍcCgWN}?^kIߺeQ`ۧgғqwno?;Ϛ}nr,ym+?b]w}ϺwsDe2O6Trڛ&y SᑢQ`fǯ d U8rV=~Նl@zWG?{snx␒`qW=p%'=6C-C#-[$,D<%sůy{0cuT "Hݖ ^a9?G%JsQGAgPqKN7~^ϼGx~lVKԄE;O | AImJ#Fv{eXX*ch [iMӛ>ܗYAFŀKI*2@a0FmRn F9.U w#8^P4*n ea'Gby9:a6=&lL/`+@[!85|hI(٠d# ~Kd$c-3ime fDVwIŨBCΧ'izhAH2kWQ~cl 7&X IDATܿ 9K?~!y{xsk9ѥ6p'!qhn}zG+U,P"zZxFAߌ#ZinuDS2$gsV %H7ckW{NXe! UB9П4D*F&+]gO473$ՙj䋷NAڪqUWhBH,qJ *89[Dd GұC'RZMG>C;1JD(MQ ,}Ӛ53Mܮx&*LmYg@ yV"܋(VV Yĝ(s%+s_9gZצCv_6as'mi:KNztϘ}s2:2ZlNq|PK:2(nyfM9ғ>r[LZkeVHHy-?,<5S4OԷe}9Ϟ?"={gS gU'3YNDkbǘ~F @BF0bV5<%&ZElRKƍLTB6H oTL?RD ݒ_AJ&k{# (t-!6Œ9ck %J2l;Q6B D($sKHs4ڳvw v( r^jT$Ӳa<7ɤ2Ʉ#e9(jųy JV"_ Tnӊ"|;CS6lgȪ4s\6|&:h5.8=oh~{+=r{.n~ꀍ]D&! ]^w/w]op^Ԏw .a.;u=?󣏽zدus#sgLoXٺ\EOX7s?Ȳwzc"} M}%9xqKn~P~6cJqx}R0q _2YjDq{V_] rM8ҽ­>O§ܒ0ɟ}/X*"Yeh 35mZ0}-:Mx]LhrTD8W(T*<(i\Uڕn*?y ,G?̘9aа,h^p^qM6 pW=2XWQW+$-lFn;UTiUGdu\M'т'k"ܲ~8E hb(P6\lhCV}.41|1Qਘw.w<.tZ寲TC_;1 'NP+/# /WC,zbE~˟skeHaD8& ϣ[nԌXشH= O]AT9X5#{c8gr"3\TvN$Ig69ŶD7;C@-EU36!$VUno"CJ3]SaKo>rSoac|7 ΗmݘFQp ($OGq$sz@v{g 2*I_/E:Dd)Fv ߕR3bB43[Zj#gݦqdo ED# d|YF7+T"d4DȜyw/r IFɟtSaNoM|h &!]!=-=HԣdpdBXR>(ɾ=ihaFE-E˼vqTévޡD!aoE-IrPlVTÌrYDhE Nm=*=,("̆\7Vx.mĚ-+ {-f/ /d.rusΧ(IbqU@`rh{C mPioøU|°] d==d=)#D%:LW wAUSP$`Ahr3sk`Bl_kM78R]&"F{ۀ1T=SHP !S g `&qz4SUĒz-rr̫=̟4JRcQ#c*QyiStCIE>S#4U\<0r%yG;m'YqɔYNPFBmRL8XQ.)ו%ᰊ6'6RFTr=:#w(%啱'琚 ': z]I\E^\i!6&& >pUM€< AⱩqJ&kmBϓ,اnR%da"+L:I{NMjQJc#!.D-Ls1r'N_`?`APx]KDblZyo&.zvBk TL@M18MY#O]4ƚnk7-2 tn0HfКL~)(e @}B^*Ae)] !HLQ!DTVBw{$$' &.P,%WӲسPgqi-َ5{@=YCZ.Xu^ӁN2o"!~E*RZD(19{,pZ+EoɗZT$tpOIhPѬd9¾4x,߬m#3t=U@ oұ<.j&;uL7Alz@J%TϚBHqH`ލ@SF[ _*<~ X|;`8':eB@pu4CDE\8,*aoiBEDTZLVxh S@2L?S#TI7lUÎRDĊI Dɬ K2:^%Q AԦn܀yfD3Eka u6+<]0忼X,T(F@ƻÃ,G1G7$$ˆľɆJ&iр )iyf큲 JA61;_"HKz<̡0S>ry!|\Dl' 4%u`zbx!-IbxeSz\찒0 NHFAr&N2L8x7 DZ7vlҵscK XbZS2 !SX_[vJ:Hș%޲i>GJ ( * (kA[jbXvCIR#amXVn/<@%b 5B1}*IpQFpKP2v]"P6F#(#lDSickgFq+=3Vo(IL'4Sdhf T!abx \F5 BDR|D,Xp4)[,s1W@bHT3ѨTʘc!G85rAf7Z4UL⚕}H\,53\p[(wfW f~aKp 4$VClLr-pq8IVz2F35hd/sY2 rgBɶkeŎu v V{J! H5%hZ (0EtɁ`ƱQ"MQ3.IG$oײqԵ&bx@@PguP%5D5z, l4,eUjfFz}!0W"8n[n 4Ά X¤(Heڤ Iler LcWdv1k,>pƔP6w} _xkGi|_^<%hZeBMH%TU#X4 ?f9_9+FdjN\ۦ)MR@#d x(?U <Qh,ھ!<&\$dғg 4`W#ډ39 kdj-EszA $5T( :w9qQ?$%_Lwxby~f;M[=q9eMN+k"?:WKϸӻ}^8f_2" Rh|j޳̏d\)kP5>yTzi,?koYU ;ܩVQPH1d TfQNLZҭ"ҚNb牚|IV38tڐ"hEd D (nݺ}߳W״yo/} wύdN* >#NTH\V*tH:i93b81E4~Q\zAbUq(Q 3.jO) ,Ve&ifVub*@u" 5Vb -lW'9:~n yD1ObާYࣣ<>Q7)T:B {Clj&V# ;Pn HeD-%FM%u  )]H{k*KVh`AVaB),YHH#Cݩ!nG:F[~iЌj,T#r'3#C3L7eִ.5DZÎ\wrf8ğ]}Φ}o}rnuG"orWo8'֜qؓf[߹}gӎSk)V^#o^wBS\>+N=dݶs{ͺ#^#/ H]v8'/=sWw$}?[+ym:O!C_O~ƿ̇$lZ IDAT(sM{r3}~B;?; ~_ȥ5gnb;?="1132НYNuv Eg_Je2!I4 p2Fb-4uZ]ʅ-l`zc6Ifz#t'Qbh}R{T&7<܄*V!B0 lЮ8`{D`І.K >acZD!%Hbq!j*e$8@\er]$@9]쇝s#i4gw\}?#~冓g'~GϽU/=7M>y[oijC}GT~۷2ЮBc~=h-;gȯ䩹$ιbݚ>3RÞ{2X#'B@_M oN#|mOI?s]wpw|/VwU}I.xi^X6wk;"~Ӵ'_=sldEa,<xؗj12TB|U?cH8#"A$u2N<'vñl#|֝_kY|@ng{j_j?k?Nha|.~!K|cϯc{t2F)}l>~YCͅ5]!L?=Oha|I#>.=خ >]hƈ, VoA:HG4Ad 94WPN)k]>&_7SCiW;Dy$bXE B;t J48 -lAJ%2LF{K鍦@G e;*jWaʌl;G RjXpp_Nx ,0.(PAzOsTlXJwq(uT8[/#®w{Yu9sm =9@g?^cϭްmtS/]_3vk:ӗO.@ ;|}D D@Dt[ok7ՇG}'< ncNxS|.>W$xl [Wj#Kr JxvG+ =hCG; 3]g؏"yS?~p^+Fg 4z}zBThgaB/bJ98"2BR|RvP 4@Uu&fRggۛ&1`F3_zDXgqbzGm}ĈgmO{|z9] {u`ïYF[Ҍuu#{Ok1^bd@y5Þ8 _K1♇{ g}i/6)rӞFGwMUĔ2IcdK4]K^U38T֦})$"yAg^Y7nGW/W۠\djbk ϷF[HbdhE;iw[ i(¤ >ؤPUCDp^s$*9r٬IpiĐfkTB 6!J_۠<ܴ$*egn!? WNY+p]]ɢn-IJ2m$.(.:K~ 6 ཏp7n;> QN.~sC/XȊ1;xs#=޶sƇzfʹ<[wC/N}.y{o[+F `rvho=gO=Xw%s՞7=|9Gj7>|KRlqQ"@1;W++  Xˌl+iUsį\1u#hwBzɋϽ}sGI_}+]{֝2@sx˿su{j{j~u Fs{;cO='|'LY9y9w\~ڟ=b򟻟#7\$bi7,YAYi{\FLZ,gd}ucycF~ə2 Ӳ).5 dDHAئ mnʱ@iMbz%ՇH<.A穌,y^ @H)U*ᕓ{F3WI7ۻedsCz\^^~߂􎔃IK,FպĬ'aפD[7h@ZdUf;vٯ]ԛ bvRAVp! &yɽp#CιH#"Ъe^9sױjB],~bܳ^C0h(x'lpW $3{SN~虽(@9woXouP8""vOp]ҍ'?ɇۭk}#Omk~wZIN:&D}8kv#MxaOo'?HS!^P(|{vWo:g_DHv#gߵyb{B=Ik[1:G?;|ݓ)~oEco|S{ןvսG%@V#gݵyb_u)Ly(wmuG(.]+َ /ݟbA 5^w@!Oy7z}G~f/={ yc;f oxsN(ZB 뎊n#>lzi9 i>: U)\|_߾H U~i`w]}ѵPN" |MN~su]}Q1~v{/scB>er0ɦJZs~4ď{vi  v?{/{c'ɱu z闛 .-{Y lX(oԂRYI"q*Elaniu*S4s@x=+AUh^䷣\'ʮrd3ҙ+ o#/2M G4"q 3 dD9AH` .%$jYgB-b'K˃J9g*G.k-WҾQOQTt]<}-52v3 'wcoAKua O{͈ЏaÖf:׮;6uZl^{ OyK?8mfi=u?_oW@D5 [W3Wfǰan3 ]?(zF'/@?zΝ?9Wyī_~ 6;!}fGϾ3Mwf)?g_3F3[g989~j*UPX -~qb3[Wրo:wes~HC3Ww#%C_l]s췩kן>7?,tYHse]u/_=v0ܹ ! K*.9%[Ua {^؛#ZZC.)o7ӭ$sQe!Ԁ}hU+ ;"Ew9߅(~u(Q __^A32ReTA䣹3m (-fg#QITJi=K2לP4 M YQM&K|*GJOc\kSAă+3z7Dz/Tc%$]5gU!ɕ絪?gD5"|[n8?~FYwЇϺE [V^uױ1Bz 11VKs2!7bt'b|doo-ݯk~G.:z-wƓӥ+F䮷ɷv /[/_-)Y=w~wV}7ݿ5G:wvvVwoI/9#֭_7?z\33U*3/+FޱOO5~ˇ~{?ټc7rͺ#`!VF@<}WMںot19 TYGa,~yWo>L7 Y 5XlO74CIpAe:駃:g!{&gWq4ph $}:rb{7,Vk<2O%Nj;nZ1#Sh27,YuK Q6#rb!: &7K6r59'SG 7ޞ2wlQ}Q@[r5Qto#b1qt4e^rK&vnBK_4@1/gL=9כbۜw RcDā*8!iG1:C.>Е4GE. I@f/IȫDzEl&GՉhC4H f7~~m)N Klُ \|8! ]-.uj>q_Px(A:PX GȡBP L>qPܴ.-R!B 0mZ*4<:eCq(KdZآӀ7h ngΒtAE>>_!Pܠd?yPtERhhNrPP_%%&^ePԟ7Z~_Є|LerAH2U6usc_B~tsGI߉N;vľQt⨀tFP)qyǩ%nE!^2(:GoobRP'awe2%߉$=#KYs7:qcEE|If|t 3A:d5jbFsxK\]E=m2|)%BXn#$mfzUG+BDEn GZU!Wʞ^˳=puՠA6)HAF"\;k%Jܫg]is|2qɬ&$5+9a y g/@ +-,P]@~W$#hJ}tU@W6P?_n4uccKU;)FjĪhYWsy1za-|dߣ@(+#E u{5}zqkϠ\~:P}yeC]Ч|Q#dx^7SΧ*5BI+AnMAҹ饪͢k]3NΥ 4%,Pj_V}f EPB3.)S;@M3[V_=4J)OaъyܢS4ϯ`.)>C=>t`jU",BnXxT -Z̞?T ђӦbaa! 6AyIL^fif`i3S n>0"cb.}#}u2 ڼH@ 9z/ 2Dm١QZ WSWۀHf怾qU2t<2  J:di\>5HGEK/ zx QNzLz wYeTCI}9@g`*B+hWt[>cѢѪ1qE[@qϞ]v|ObqTDn P㌿DI =WHVq1IXWoHPX2t>b~],'DhdĚg/\A1Wλ>n+F I.) ԈTTCq|v;ThMȎ)n*y`&$.aBkg27&#H0 (x_mPY-0sJdjt)s]A~^#0^ +҆&^4,:YĿʒQy.2<}7r E`vAX"Z93^i\@6 Sf@8jS&p N[qxKX@wU=4WYK% IDATM 6>ԗ `4'j~Kq l+|8rpW$,FBR[`%X3ݨ"5!ED{Dy)/jgYE@{KsXqAng(~(3MwUz8 ١ѰjPisÌjbCO E5'$Ϸ2T} A"A(Q,@[BT t,:W!!E XDlpLOjDkIG2@8յ2yL\Yo£}+Ɨ܆Bg5$ Q,>[#n(A?ζ+ @RU8: -ڇКɐ+LQska 4E_$^sG4L&e A3PA?:ީs J Mv&[ al@cFͥ=AI [KcH JteNl9Bb@Cst pǪ-ĮZ֦X#sL&ꈇݝb =h㲡PU$ό&E Igôl5ݵN.S0_ OϪ,&949ٴbx>lN QePV]ied\@:²#1&@ W c"bk4>j]uKxحD8Sz/AEgLE D?؂2F@VٟAE*kha-8 N&,bS0]cAd=*o6DV6+M1]K,}A$yV^|hPEQL~YF PUPby6?@y:umuȈ]sNNWZ\Ld$`RE c M|/ۙo6cRM98 ;jŲCC-Uyfb 0ڂXсnŶ!Hrnz?u% ^失ӡHF91R)a#粏q@o*Ȼ?XAU QQ~'\|Bp hIm9zZqd;wh[@@ Z }}= ǖnՊ [=2r;Jd2ŒK>6=ɉhRQիjUWcVù j $5WϵʩR:̉ !&lRA g.ebYw а,ͽ*2ov47@Nz~f5F~:43Oi;o+X6u%Woﻣ 8"@uG Ł$'q** //[^+.gsCR@3E|4͗fo~=7,U"b4/ìn%?5;IEWII2$Ib$1?ݑg&U$ 溓3](]¯~o?nڜ4冓 izJ{ʐ/oFvwdIA7k6.r>7:zw&HT:+џodZOB2d^Z=H*N!TMbS1 0U ˥%*#$RrKQ]>4 XA %ƀ+oA'@@ '\( űnQGYRx>hFN9oTx6| F vuusw+JA*V&|坞ۤoa#PXzlUPG-YWB3 ( (BPYdkYJafF;%JP׍jK䋝lSD;Gvu?y䠿;n>5~˿53mo|wN[;f:?ga*z1}{{١k2574:Ջ~ӡOrcuc݅oܶ&wuz,LÞz~p($C(jf;9]HѱCs^K# gs ntB gثZ9c <"4pؗ g]UTYld uD[0 +0H xDhP5 gU k̤,wTWsC/]؇VĵuM4$#QH">-.T5[{ShL@8 *j>U}FxYfb:vz#*rڂlp ʼJrFB~e[vN H1%s,&$/9fI־ɐLuD$m7T7̷q4ͬ,t6+%.`%̕"Jk$y& j?a{W_(5.pQxfHwH=ٲ[SmOcǖ' {y3s u?|׉X~ͻCs~{vb$|l [wK=W[#XGTZt mC{J gv۸zU~֖0N@Zkb9q`OYg/ɁӇzݎ'-Oos4&7h/۠컘n&US=SJL$= 3Y+PQCa&%ja+K7cXQEjy]b7NR^0?<^^$#0 O!4"E:R0ZA !M-Tf6BԠ͐HkCˆH}Io& " qyĠL4#* Dz)T`/ 9Dj` (a2Di 3hY༨Њi'Ph֣ԥV 1"J'ظ.#;utE<6 [i0Y ,0rgUe#'~p#PypŭkU#s1y7ؼ:[>pꎣu1D⎱x%o'BoK;m$$~|DIGxSP <ֽp7n;>y|<&]̚$CW8#ngSCEIm)X%i[.#SPi/ sI ^IĘѯA7 S)$YAIG2$i:|]7NRbyV,ͮ*ܸk޶cMP9J03B̯#S`\׳l"g#->Ѻ$DPmPit=1_\F/"jn⬉lwHnλ[4d|lW@hf[nG$GAjfe Ef`Fa.D?nC=Ů@5(`EbG: ?y p=ˎ am-;o'eD@t]EȌz忺E~8RS\q>Uv؏Z6&?u|qv|tqГ/ڴ}a)CHhghg4+:ȇA(ӳs̚zyM ?u%b< j&RAGPRW~r& JQq}D\P;=\ud/9Py˺&5Z2,8JLӋNp9LcV@vyYG jW8n XiTr*{aMnӲJU65c$$ j*YH2GyW1hN? eP*널H%9B  F[6%#Vj xY8Bv^y-tVMGB@-p! k QPuItẀE Foe*RPqfS-g$х_(:iATӫ [W~x~r")wκתXuĭ<-u}ߌҭlzȵ1^]'M%sLX_E rHR*};]:Rn\ieA817B?<,R/}v6F=Rt /m?J{rWk,ܚhz b`}tә)65' 4df#I%ignwr0ZK92wgWc^9vtBO;v2 ڴG( ~HY4Z#?Mz2d [,`#b4qrB*X:JʲO0Lh[ @bYHdqZ*j#| %}&"bI3ݸCG;#6M3H{{fˣfXo>@Ԭ^iّ fqN+i]\R:""a;pD!ۺsw=ynar0pN~ VY~-V3'e!t(/kҘ;XrȐ*]CJR*Y1 .v6l]uQ>O}Ms&ml|G}qyn{izvuuq8Kλ5{fG>7]PiG:y2 ?z/j[_G=uiX@V=8,M\1 (*̪ٚh 5a|ݯb $/vc*a iLLme_E4IZ*SMo^`KRnS2u@N;Rc/f7زs 08f|yr9u[*+_Ġ}yǬIs$:b&3>)uM(a Ŗ8A፯О)Ap]%Ɍu[Vs #"Im# e# BMzrj|¨yDz"`_shSTӻ)#wJ_H slJ.;*20tJmUcZVl< h _8f?@0IqhI=8Κ0AH³X&Ț2pD:"`"R_@c j&ɺ̭+Fw@uy0vBH36ToܹuZk^CNR:՚16#N8}VlQjSX*r2^;<5n45{*I=G?TY^/fB\,%U<ܰ^^$;t[\^f\`_PTEyXysR0:aV5 xΫ8!= V:0T,iH|lA:'p@` a`B<:-RY4K7D(tx+ G m!3h]!h@lvKڃCd*v^vB$xi6&%5f~Gs, E6|@"3g(:+@):c7v Z*,ă$:( н#JnI&B +M/T@wU^@W)j'w`Fl (8-C#*NtfTE#$n=!CKV]t;miצ쬍e tDFB>voGل?|mZ& <]6>@{r9sAݾɊ~ *lOj(Z˸zd!Ǭ1 Z]itg!y(Ŋy*#6H!l%{p9C.fkn ltԃF`VpГ d mV)S؄h,Y4ڂ}S5<7ӛDDqAVS;"Iu×f5^Lǐj?CdWR #9>EhG4uN_ .!ށ7UUk-Ͷu9:lHAELdQAm@|l; ,4rZd!gjs)՛wc7tۗ̚|$ݝut)c9*Kh,Dvqcvt=rŃde-jgYtDMo~y߄ՙ_X#p(; ;;íW ђY.A> 0ڂvz!08Yoxg:T7"ƪ!D8Nu i4[0H3)cZYٴJ mGa-2*Y8FVήI,:PiES-$QHQߛ]taɡpa|mf#H-i4,"-"P tOL xc"vuŬ`n҂nP~4Gd<ķi}XihvIsFvt˴}Y=ʔoѥQ­5ihGڪ6#f ?+}Lz/Db~Jjw[o LZvs =uAGx5J>o@U!Jd&3dߊ@VAT٩ jS UnJ|tY.Ud&RΫ؆ 9y+U'E?nGHr=N> ` -H}^X_,Gt#/HXMNIS.?Ԩ"v "!J<N>ɢ P-&$Nc?H$nX|C Bp3i'+@VTPo$]<<7L@@Z}-^Bz)"5" `x!2 x|DQ9dbdź`Qfĺ' Amwdf/;Qx \g A.YҗYgUPA$}דZPjM$&0/'$whXeI5,н?yPX, $l 8fvnCͱ"N!]zz bR JKstm26/pʵ2dJ6jC*NƑmzl`g"9J3*z`8e&Wpkbc\pRx !,@B"3s8t t4HUaHsG ( dUG !Ȇdc,JEYʚyF()"BDv)ӕ*wѡ| o[*#QF4oD$h WF$>=;[M5uTg>) lsP &$ƬTOWSo (u*%e9%<ԺغHs@Tݘ .K ae\DBCkY't uTټ)ӪW%MR#٠ 07u sr=:s iP.;Ϧ%ȴ4#iI$@ȆUa|Q̫nDĬҒn!C^ dYfHj%5EB YyObD flr:emm腗S}}I+&w/B%hF rB-X>ܖ7X-82=u~rN|0eQ>1APO6̹]RB4´LܜHc#͍r0\p'xv>PA|JB6R[rh P;:Z(V75  8xv3qێ4q`Trtȓ>%$,d3Y|;k{C,6RXDHҶXF[YKOzq|FA5MXѡ8LuiY9F$120q̡ / "lH5 )U@ :ti#O ŐpIs6˺^G!x3Q;MwJ+V uvp,sY6GQ)*ь9o!/}iXB_'{"ӒT I;:0)bZC9^eHܕqvzƾ*ǔW &?>Wň4HL*AqYb-GzV1lˬg~ V:ԭ"M[ u*Gلa"r^@6J9qp$FYvs۶]5A=bdؘ|P$.'Ocڀ<3Q| ڹL#G"a8gS ;uR5g>&Ed hL/jM;k"ԗfKۺ9Qɀ<9$/ )/*I'd. ې¶5VSyC1 ?$ì@qIOTuJ 15:K@&nJ ~#X 5 9m+2&4ջlUl(␪5Y&4X/ŵdF@6QҡFZppSM٣fNURcT7ʂEUKd^ $BmUȓdEkdXrjSWs.og٦deל'$^n7& 3 :)r]]+B6B+GGB9c&G ]]K޿}TUhVǸy+>qgǕ'h9`ӕule3\e `+ +LNyǰVf@A,{ϸGHyn)B7S5.DtFNρbn")?Vܸ:ӊd]"'sl, YpU&rhrn }:3B SᅽZ9i՚BϪ;塀a1¦mO/NLkkPױTG1 D@Q>G7<9! CUa*e#U72{ZksNQ]x8u}07NBRt3-@EoF֣MDȸ?;Y)5-`?7ob.sT4Rf3Wn{gA2UQLm4,5.\BzcIqMSQ:BBbaV͞ngOrJ+#UBB}Ǩ3P)Z0.W A?W) TJ0Bu.6A9'6jv,y^O3V1ŹÅ\I}I@ (~QW2DDk+}X[%FPt^Tt%B1 lk6`Y;`8GGryNv)NI̚Rs✖֬ ŘvX#^^9 d02Wb%*L"Y1\ NہTރli>uTx?'hXb|MsbZ%> s#PѵѱW<]]Z''ϺZY|?ԥ~{~'>?_g"Qk 1MR_x'S?_^;;\t[{+׈_OW=eaމ?F G)e$=i ߵT0Qat|1vmS-@ޢ\!offVƮa "} ۶̓}᧸68G3 5!xZΉ+&vY,dWJ4vHjD@l S>_ƍWYpqrJ*?ë%cD^Rdzd3c (KJT>$"N>u}J)DwRsZ_M}~T,K))s%ɘȮ!5GyIO> z*xWS*uJe`bgL(j)4} Agq<n8gΜ@iLIgYWWe&=@dpK:4Gu էZ-̙9CV.Sǰ!U+G2j\G,tf^'g>O[o}?-D_qw;u׹?Λ;䑭c~ʧ~䟽꯾닌ocuj~}?G_=Io7J?~2x2~ѓ+LE9w4.6ңTT1yRmQH,%!qpFk#j7| k=60t1Q w,V1=gppl&m4P+R`u؏z0/xõ vN?;&]t'Q 43ǦWqeFڥJSb@Ry.#VU%M1xI&6ClYFSN\'\$lXeyR-^T%sh(%>uY`O )VU{LF}NKŊZ(Kk'D{g3T-]q8^ GD z}p$zǃK>{Ch.5-jRȦT%D Uf~-T;oΧ&^qzsSg<½ ^=;|n㽟xKO>3nX_s1ӗʟ~?s6|讛of/ s+!$ {|GxG#| 术ntן$%Aքrl`ց^g.rV/W)XWz BY_qK~%i:_̰gQY+t9!MH\ $51(\$:N IDATDDj̔H~)$T^~pfcAOE`N=S|CV#N\, XB`Ч8spyxD3JlYQ5hh(uԮ=rVTv'tEڲVmF~Ц~C8 mH<H3(B`AU sHfhK3<;n[o{Գ> OΗyjcl2E*Y_%${3l;\I/$:'́v󅭃2Xv_41+Zm87K"`0Q$Em(v1 ܤm_W:fmZ5sFQq[z̈́Uz!_k #n^LG<|q#=+o9/_0?}+oT;nJ3i1n:Y%Wam:!Z<p 8:q՟)N gX n}g syrX䨈KRy/QJR--Td%0~um2-W&- ͟wln'yVAE,=v*;`B @T, @4XV[zr{]" Z.-q|ooe?e{OUUF*'MY$B7^7F vcu45ŚB"a0Kjfփ׿ۅfCˋկEܲ}9,-,y-7g<ܛG ُn̹'pem;beNÂ5~Sv񧜺pCNF's,2(/ ΜB)%, &_DK)j:J )QJDR(%B,'<de9OV++CZ̚[IyݐJ(,4ep3ݶP%{$"5{KPd8)I!'[G4gNf}C 缌&ߪKh%}B"Y(f9 7iCXphUS-D61HOЁ ;#Ră簫jmjf5 I+')K iG^?xɅ+k/~=Oғo/܇Nv/.2Ѳ=>ɗ>?'~˗yO;[h;{_'xMrå[se=a 2 /~=ɟ\ImZ*3uoy gO1& "~@.Ib9a#ji##8nic*01g-Psu;kλnsC?*{k}cj>u,~Ìڞ'z'4雮vɓ:o\:Xq*$=3}ey;4L5Q՟K$)uRB% /r֡|9/g; %Rd]^ ZDc*'ZDX3 L|9BW̐XPZt=6Q!՛Re@7y<%1%0~uy>dΌr`G^a-li?L{T@^CyqÜ.i"կi#c"thL[Jkkg6l 2.a԰B셫?=wGxq{>7O>}t˷9Mܛ~o{7~ُ~;߲Xw="[vW&%u^zuI|,[g =^+5ybL޶Ǩ.ju[I2 `P ȕnpj)5B8xyDzBfF fh5[hj]kH,R%=,D[''`6Q x2"/ q8׿VRګuKW@,Ytunhl2 B\6F07VQ7*FզW T`FبƧ$ϒ*P{2L\'S)e[46Lxd|A y "ڔEmE㑊LR AQ&KPHa/:)n+~ۿp&M1u4FOʹ1uo>]6EJ*r@YAS vDE\Kf.7娿T/ӌH |қ7^O%f}eWpOXO%gcWfμԼ09DPms@Y?:Kɼ`UAB–HyhR Vdչևj{!XY\׮+.9-)^(艙$ذ=҉FO<;J3:r7l}Xm : ב/ksتDJR"(K8sؽe].OyR@xB]XMS"UJDTk!jB.* <ҙAqIURX($|jdՒK-ؙ>zl]3p\*u/QVFP@DAz4_jmޗV =N`YfYv[Ǯs^.tnY͏j@$<@R1F"t˴7҅Ұ -\5ධMKBl6&Pqs$I`.( "fAv3k45ky 4s*0_RAj1+ULrSfZjM7Ƈl{lTllQ?sjUd)]9}IT33?Dק86Az?˔ E98 WeMmBE.&эWg:a}`LfYݗfԮtBdῘƍTKR62P'[kjrm\mjFGS9.?vuN9/ n/ 0ێaRThC""nVCOhEL?l|h ݸ5mԇ2UmT/nի@ D-}ve0U*kͲb[ݠD,Y\laj~҆@7~t娶hÄə !Wo4;&f8ԭ h~RꥏPMc0%  2YT9O-(hh7 ]{Ӈn&g0 :cv@&䩶L$ŗv'CS/ru_RnmO5 R9{b 7&mWY`I$ЦwRylpRdeA{8F1gY±=ޫݽ9s^譫|G< YM9R4O)KnP.`XGpQ5mxgQ;&`-jW -o&KHB&ze(jgx^T1Ko\O#lX{-җPB '\l?4鏑ÔWjZceU| D;d *-T :ڏdW6H\Hq^ 1."lVJaDyEv,v+o<`ϒft 'Vi`A|uU2S[/CR MB]ydYK i+92OB(DxqDjJ:[) $ʼnsy!GHISZ'TX %lC se{VJ̏-r13g҇B !jFCjLϘ[fƐ5(ZPGw*ˑLs|$atu~ױ"4޵K+v;ݛ]gWFɇ$_^_N$qPpϭ'ꖩ'UUg\ /$DY ]Q5 [)m !F#R%UY1ԧ*c0GeQ4BV K|yK@7)XjJ9 C[t>KpF]+_U@ vj9*M߈!qZ HdHp;7~x4?q|t A8QQW/mU;ѥِQ5BdmlOhNX-~} ? G)}sC=Dͪޑځ뼏El,yH9dqB[}[eXV)kQCrkD;$KZ+,q0Ck$vbn%j{i{4\RYY_:}/R=eƬ*& [3 ^]6Pi@<4[MhrVC c'ҕʽ =eAty|H ι^( zd@du'I 1| K^F+xUɆoDL\D*Fȳ}]Mɰ4JQoKX8̻S UTpۀ%Tʉmj>Qb?9р |I12<;y0:PJ92(LPJ syp6Ҫ| H> ZuU`{lšvh7&g٭hȲյqub{8NݰB٤wiy06GTUkI2![V\ ?-K5d@L&wjDSӦ r˱JJ,jk D%;ՇjYnySYRm,RqfYcZo Oq?%ZJ2; h vtc-qr12˃KTfBVMJ͂!B"bNzLT1e|L8ȭ7 %݈@JM bHdB>IeVp^yהmGd]Mڐ~3GV:=b+HAF}u4D TE~IA4@fuY P"g&Ks2<8Su8O[Ax9L[Kz翓H&uPn)JO`R1UBw@bZSu.VTRoa2$t%44%E %CmT$x*EDvJ(t;19DoO%JH>[?Ryl]Ɛԧ,Ɲk]3lFzSfGvJ؅YI ʅ(0bs$˙*efݡDh+fuGwbs5Yhc=a rhb IDATg^:4d,KJ^r%2i 'lSO\4;gdqGSi2O)Fe/)9+(ևze31 9z((pRfgw-Yst#hQ| Q7}@nhZZԾ&]o7~ko_>:5oW~ ?R4o7yk:dSV>c.# M6ڷWözOӟ~ };!׽]! w Hhݕ/4%u'pug!Uo0N( 2HPQP\ d7lI#m T)Q8v7Gv@f5 ZcIz?zod`c֧9|~d}ߪY6&tU[y ; q,5*=AM^s67RMC¢uu mȣ=OyZ*c,7*9<Pkڕ"m\YxՃ??|+W|ًPK۫WfnkwΪAYOW=ֽ,>P KkWv󴵷rq{ 짜EϺ&g?sϹ<Wī_5;[ j d pl@IXH!iRAt>}\0J-\%Cp B &TCφaʣxNQ;!p<}F~ =Fd:V{'?P^HQBLR.J&i,5Q" iʳW\8k3䜧J$JI*bZTaM DT*Lx,$廤9WejNŠU$W坬,p!g}mg+#gEEV !NGQBݶCZ;\d]f.RwL}ySzOZlDYRJUȺ7 ŝ٦nQz# @^efj~q#-#a3P)|Va$M[d~M#'0lWi7=o7~YEP>zb}vx\oT%-sbnx,};Ϟ9w-3;Ϟ)݃MxV(<̤b JAUgQ@dmM#3lKa- ƅ;(="k$lg3OǏ4A7V7ZO&` vFtDP9XՎ3sĉ[Uf⋲ 3-uқm.Xx7LWՓW̸,/\Hm"U}erQ3:߮b=s=EUàAa 0)( *"n %p]Y*"=)w=y,Jd WSDE?2hYQ2O;,ؽ<*1uEx%CS?dWI0Pfq+VҖaD(̓#gƶ!Eu a<%V\)>vͷu3@(8.|=d=bUThmw>;oHIk@n~ `hb%'|sW; Ny@YvjH&n$,(8z ȤUuV!,wNQ5T4)3Gx](YCZ%0{^G+KoŸ՞H!d= |ˣع;uUF5z#JKqƲ\BiasC{-ΕZɖOPahgrIitAvbG"G?AW<uІ̍7b*ڬ@hYD6!$}BVb[ mZœq.obn 6mV+& Dd@s6_ L8fMԚJSA3dJ&ЁϨbGMuGd/!8t:0_W!ע 9etXTHI W}:[UQ.x7/1<Ƌ/||+ֺ*0d8`Zv'f;Pg/n}OV&r_ijOx+[Ln [fgϷ0#DX[)WaU^ S3 6Qeh.cs"h'^Gnx݉\J4e\n!S #ןho !*TF]3ȥeW/s^](L^#?6]zJ%Zr?2v9XbO@^j^`؍7S8RB/ vl卻`SnR?CG|s; JCv*\R54Pؘ\)yX+E&#~=L37W٨q16PT{ Oy69^^]%/xPvt+rOSs Ϻ烯|> *P[OJ>?zw''Ize21B?3n|}? ?ޞCR%Ȋ.l ާS]hZnV5:FD=a 4 uF>Q$غ.-sJC"flb?w ĠբRqy@i+ _Xv&R0 G< rԹGoztRظl j_ɃT1uNj.O²Hݒd],.O|qV=(;NOK}Pמ""@G%,npoҸe`pGʇ~BW ꩒jҀB7#ÿθf  '2@o!?66:Z<ڛL$O^/hȍ)7G?C7~Oqo~o>i|/oٟ4]5Mw@БHKI4BynwC'ΚWol_'_?uoe/Uă'|_ٙU9ED8ܼ֩I@rT@ɝ 9ήšB.;1Fqj3 8jփ$ a.e;5:(/ͯz±I'f ykVc"ccz>\g38*GJ#UK}I0T};!i3 +)[*)ߖdY')@sҽl7,BN%H(6|ɆyS6bfLDO8ѣ..q`uQȇ#gFNVTU $r2͓`+UAΫVm-?D' s^^8£G͢Z!h SBK8A~лjX= Y7_}[C;kaus`q8 lR_Fh;2iUtF*3 ?;ƍGxknO~ǿgGL֥pTE4 4#F/p51<窧kiM_%vFGhS{p+F&CihË"noOl.2N`}%>~fexaV I!VB|RSr&f&ÙY~bO^OS"ּx L @:5CJn D~WiYs@6D|h\Z, #3d9ԁ :9+欷@D(E~ 2h5|rO9aݡl1i1Ss)d!ԥg+e1X!YA-'[&ız0 XYaՓvŖUlPޒcQuBd5Rt1xJ?_4C=fi/OGՀ^ja͞YoEQs k w-һ9jGxȰgzE="WMx!|MA#) ivNl.3YBKbi^|;:98z;HI ;hLP;H)< bTAiΕ91Iy뎾|KcWC![-+Q*_QhNΈ;ͫ^/M#?}%HL3! d^Ȱn}Ι_v9VÐ*U E&6oՖ]E1^Ӟ*2 E(p2=#s4?g6uGX8zTz`x|Z~Cv'> lŒ;-c4iPUSI5mA F-l塴nV/|+IVysn}9xm3v`?keZG ..UvgNցjlRT]oejv~E[_ώ-on#9 v1V3}v~eovxd$2-!w'm&KkXJL(<['**\4 ȊKyŊ+ؕXRU3e;3j͞pT`؝Lϊ# gĊLd%OHZM&P6P0K*mm-H.Hm ^V\U ik[W嗐Y0ᝫϲ ^F5jPj wBkN30.h,P"B741!eLIY"gi@lqgSfən p4l][[ej8~>uBl*(>;h:eFCg_I_ĤMg]sͯd:iJ `ָRfB!X aA%h'pY-jv t}`pԈ( <͎e8g"IaH1M|8Mg̈́PMr%[oRT >.WmHO Ԅ9Y3a'4#VwM ™Gm퇠Ƥb."Tψ(CJuC"̉v@\Q#aBy+MMA&N H<IE, VMZfjݱi#(%r *=(g` 1>?ti`vιȌlaJs!%69re" PΪ1U:#ڌ KsU. %iK2@Fq1-JtaG1nP7O k$?zV`,wX)$A(:U ɎtfcFqR10Lmk8{t:RqHV[$A]$+m,aµI״YA(6yB+Uu+ULx}:b-9]mqGNV8fFwrѝ0Ml4߾D j  ]˥׎xsRO]g/P}ퟠ%cS &ޛ5s,|嘪X[w{ߣK%1է\І>rғP6/"뜚$}S:O& T%? ̙AXف_:d-sfdf5p/dT]uIx@sX!^nȗo6 1pҬWܟgB((^U;QC 5r?y1]j l]çDG1UOIC)gA11Ȋ⊰f/!12`%Sڱ> e굎a(F~pnX"}/ET5dV6}IFt胉u_*+ CS퉀-]K נtIh=~EOUB<3NP"nfw@jyb~ώ4?X=6֖4`kʄ4ak> pRC)le@p8iJ "|QmSؓs!lQ63LKSx$k#Xcv/(UEFcISnYMQV\:ʋ01Q&Z:Hn/P +[!$MH4[LV uVD 5Ym< D7Ib&#>ei" [v*7{P\9Xrl`A. |ǘ>BV|?_jXchV/=-Jp,X4'é13G!? S [_U0WV=k8NgU hHM$33żrMDVDZ.&Óׯ5}ſ&b!I*KJ|˥7-p̃XHOqPnGDVmÙ<>㢩Tvl&EmwgݹgcV WE_#]]kZ0$ `0sn:FH)uf0̫3NXsy{8ԧewe8^,`BY)McG{aRAa9m0MxI/>޳@+f<@äy˳ as&SJ~6gFcsDO{d 旌Վ7;0pוŅ(6g]Ar%`H$o/JIiMWq3" ky~t"{R ZMYqוŝ,}F9VeW%n-ʳpJ V_YY EөWCX>+jSWX_:NƤu#T*,+jzȩ* ]Xj:6x/jC هcՍc'ja jyQ_R ~痿 ϝ߾jf}zOʷ/{7^7y8Amo o Gp"797{/O};.N^~ _?{|׽R:|ës79C/>D3#j_ٽ ѣbxMmx,L*<Mő d9q6x'5d Ij@ [XӪ9H]^+P&~k;WPE?E|V$-ٙ Eh : XG#T9R8m*2(cso!@?ruw=LKr_K_>}ҳ6_~׼oko{ҡ  T Fh{ygu{?;3*Re}?[/=wik &f7Yor`{ͫ9/ڛtTxQAjpP7%3_w1 RIspXkkTkLUZQfÑaC0>iV]BĻns]f)M4 ˋ$H$Z/0EptD0o\sxйoOȀYY!>\Q[N_ ʭF%+jY ~ߣ ՞+Lr}^^;=\Ջkð0W['^w /n?x=> ~o%3txVCw/z}[G?!Wx&p6R8;Xt[{F!Ow3ʙ??Uo//ѽo;R\^Wri{v^ }kE!xv^T:(_vd](c{l!,⹭ T/N]fx )9cעDn6G :w}+y:ܽ+}J*:lNȸ"/ vFR}KȼB~!In49LP!r33fO ";*H&ۇudfP@`DKM'(8\Рa<\cf$*wi,m4$3cpgݞ_2̲ZN䂩R̦:?_yxrc2t;4v6qP= ˓k]ԧDr.(APgHc.q5-r'Qz%W/hI#!ӣWxy9Vid@Ř: iLD|Afg=)&}ӻ~o<qé`0[O/^0>rSGBxf/S:?kZ G6f%>R(=箿[o>S"|s쩻`(Ng=S~@l< jD qGwڍkFN,\X|֡oqFibLETȼ0[,VOбRaT1ql`u2Up#9; T=_a 8jKӟz?K@e_3~w_LT[|>t?ɓ[G?oc+GB~_ .[[>;o~x;ϝ=Ћ>vaRmh~g?tϷ|sߐZ;`26e Hnq[BUhFQ£[xIs)*[ynqM s0rZޜPogTY,C>)a<݆cGu<{Ǧǔ)=g(oSxtłlIVvnA cu`N%r`:`|na g@ ex8WWJn@89L j՚["H0gh7bC͛Oj-`{FMl2V0Y$RX[ jPR-ɔ,1aWq@0d0@Bʼn,Fut 9>?_F&Y dZRQ(VEP.x {[y U8m5KӿDŒT{g g2υĝi?[/?G}O‡SI6Cff^c{Q܆LƗ~ۿ8_o?o|ԏ iμmJig60Ӣ鮇pg.Fa2t6uQjSٝk-άc)+b~2r){:JZ7"89f|K? Xʑ z>p(Y.ξd\Ht uom6A!a>h"[BP6X[ps2vO`6Nж0/߼6-ZmG~{&G)։$Q/gufPNv eeI5_ǭ#ovruV8c5ɒl@ꝺJ' ]6^-jqfYAy'$vrvyiuv  QJBTQݗ[)u4΄/)Ydٮ3>Է|?: ޕFIwC CLqT̀ _L.bZh an̂]<3byc)/fJ"jBRHAR lYǗE^LjK՝z8۟#=^C`{HND5SM,wN;0izW6bEM%T9.HkFVV\.-Ґ&513@wбSH,z<}o'Ësxݷ??s??vJBe21_8zYà1oC/}G_|dS_ԿݟMo}gWH[X|I{46=7D33>6Rf>[C0;&| VdM9Pcu{|az:s oLOot)8a\d#7@tdlA(u#uu#u+ӶN:aS+e1!6-C(m6Fz ӊTc[#&vҷ 1"rw_^zw:j5f-EWRNQ*ccK]\ߙvws'ns6Nw{εeJ-УӮ Clv3Z+KjNhE]="Q;d6kun?yzﮋ)lS_+yo,3E|Z݆%ob\m~|?+?Cb;L?#/}oͯ_Ov73 ' O 4 : ͽY~K9˛ͯ#M0a__ϽZjk!4F/UdyΉ.?]"9QxD,HdTn.mx3:0EpT[( |u_}6ekIL>p][Ϝ\'~?KǗGʤ(*(6 ˁKHϘ7?+?^ُ3'Wħ>Oy SQHttfsfnIgGM.7N7z1 EjmRN5ΕZPnj ?,zԦn?2a2ϕv#ӀF\Nw؎޼ 69:ΜFk&HRb4 Ξjsw2ҶjXs4N|~CgeSP]rmzAtY0,n 7c9ٍTڦ,װnTFcFGXJ#'{'@TA7F8T8>*ˏ|wHyEB JKk@avaY@~Cn,ZHVjm>N+m4*NlAB"Κ ]Ni@c?)dZOVU &E\\0v?8{}TCLwV> IDATɷd ϼޭKwCk6}9puGNbdqw(򚖙TU]?g/#Qo\ w=3ww7*_|rҤ:FVt׈X8? ,c; .3%U)#3V[MfXE>-6%B)DH7UBcVϰ2!2S|8AS\@႟8==,{qb,1"5-sHHw\c\z3sR>t"Vɔ2?8WK\bՉ]%͞uDSʾh"‡k&12ӽd돓HrܮKʦ`_}WPz 1XٲlIBmNp~޺Ե%;Uk! ҕ!#=%/nnKH5yܮ4=12ejڅF~BA|{[sIj6]myt+JO/Z-,_j8l͂lvV׶ЕIL.`c9dB&{ش Oi!P÷:.x'@DULU}vl|%%Z4$3}}Myqc*"M*דӕ]KZnm4B7 vŦKmETY ͔"=ުz|~>b+)̬(IuR"305RەI[:wD8(|kk&:W w*̥ qdƩ49vmsNfytMcGp㐄u e)ni-Da̽SbtJ(fӄ߼fMQT6yڨMY6J:麔>܀G6c_L$HMa2SS i اE63b[sҢaz9gшTT)άH 鲁v:q{O6C!-S.lyӂ]`F[tTF0pzTq84IԪ`{,\1:4Fʬ.3iYӰ$V.u⧕7BJ/,70)d9a-ѪGM+AdNϭ)ʡbjLIaa'1s*f.(Z֛f50S'q𞁥mp f|:OG/wx{k.4kC>j pNNwط322/G6e#)mJ!pzBn}tsӛcg٩BdZL;=zzP;VGS?SP u^Poe/ z}1eXm̚T}S!:q,51PEGxړwZ. f]gMd-"=+a l] X:geWJsj<ٰd#iӁ>C^z RuMQ,iz0=Jz# b\M֔en=hZ4-Mqכ"v2$yFVȬ)J_M@u,CDŽcy}_g+Q1]ˊgy mg:^yb2ͬsmNqs[ aހ3,bt6x"7; 0ޯրWg߼[a*:`;󫫮`H7yѶ>I6gFCzM'Gs.VtIiJ.e]Zr禚ﶹt}C nZoP8ʲ5P%PlL|3l F\KOȴ 2ijv YXFp-$u!8xeav X"wkW㝇uF4.@ԄtK Óeq=CG~teJޒ_M6d^]rD_tE#?)bVT_jW47}g7S4*~͜;gsAyD2)N|1 @ݑYs#ط#$Ʌd6+ . 0BH^NTC3^]m%@~xP~8'ޫ0FcEvtfуK, i(& V5? 0玤gpdǩo:m SHEJ%fV@f:w_;&4L(bg6 #-6fBSUJ>cڭ}_Z^7x]=|\MI9 In0U5 FMʁm%@CpǬP0r8(qJ.0 ȁ ^x]. E^_$kaf@&]h:*tbgcrJ-^ %wюh.kx^F [61R\"Vȕt@\{_(?i+3>8-jšp :ybB:I ۧŴ=N'CzbVŸ!zU(3z2cH_-M4x%^ڴIpvjۊ ZJATNVHvKRw;KIK^='y[%OwȒ33]/,0l[Fרe;ԟgߣޒy}P xh"{ߏL"” On06Ug\\Dr?ly dڐWstm:LʡLN@byƩ)7:yˑΫ bRl!z*髂\s%̱kҹw]f:F[GoR N)"ujcvMH{CάOgiUc<‹~YF蒽dlsC{/mGS/T@a^Rѯ&&E>cG"\F`g\Xv=ڋ= mAhS+Fҍa.To^b)11 l΃We@ӊE Ƒ;L}cNmPʹmi85ne?b褖z#7r h%݇K}<ڞVTNu4F cߪ**ZG ˎͪRT~rAy|}~is pmK)`al] 'Q)@W21Fڄ*;r> aR!DV`:`wgG+jU !esdF޷')gm >#ҁHS:j:IK5kf?Oѯ`]߫}mhцTKiˮr6$YֆDF:F=i:~pg2L9;Ce E/O/9Wt&UH@ ů[υ'Fϳkؖ఩,T8e$Y(} s0L Вjȩ(D¶͝6jFwk}6X9ȟZfpzZs%!“~ye2w@,ZҚsZK H֢luk%T8RJ U:μp[+v %⁂*<dW+GG>g]}H-!L@Iܴ6f-ngwÖvV@EM UЄwx6)qUWꚀTu1Hhn#nKE,9Ϯ?|8v)Yg-pE/̜P]kZ6eڡŏa\Ro$ ~W۵NxlJ؈an+7{Muv(}ε#b (sBSlp SMo8ND K p#\!tB͊FQ}!M`n*Rm)+Ee)SH NIyh36aletrVpUl Ѽ 9f\~tR+'E;gDkv, b1n*O%pz@d{8re& Bbȯ-IhK32/^Kղ}-iYynfiH%,3 GJ+m7!=8{ !]2̥F[:=^ٌImVˡn{HIBr:0ڱ+5vNY:lqH:3qtDUisTZ [bloqUDqDXvTlh34(LiAc/OڙYZhm8ҟ}IG)v7|t3i)⩵T/Igx O2ԅW RjY9~%%C#g5t(.&)~S ӝYh6C䶘'-tZȞh:6chEĭuOST7vxoٟ_cۄ0oJۥY|-}t-&WXM)kBGD7{˼Ҧ\;ЧBp5fc:>_Sځ^6M?q'/ܲR-b@|./ SLeIT̳ĊNYJqVKM a+ }Muw8 @NN(+@r i:%f@QJw5c*&!`rd%:`{O!e^Fܺm$ z۲^_f1@PuQqPB+Bhc(Cd3tģ[)^'^!m7Ŷr XaS0^A8 #>p2nJ  RUbRMrq}ij4M@$I0Llʀx`LYr-p^Qk7|՘vh5y#b cM*A~G@1˥vx[ #\c[ } Y?L}c1b-OݒfAaȶ ;uރa.T攘C@Jf2 TURlCK;nFZAEYl!9ZaQ\Dɨ0?uˊD"(֣,%]U8[hU;24:1HۙmwF".I IBN,g[(UP GxRd{{ =9ޜ K#oro-~X?Rr,'g]0J'x]fcn'uHRH;3GKfzNZmCիDߒ\mmlRng㪥aI9Vo/Z [@zuHx_=O듀a sFKbKK| G~ 횭Czg)e<ykyf #:HL*n (Lw.iE$|?g+9`4#)Izp?+'o0+g#_ěI/^>Ω6pWBD({-:ĉPmF[wOSW>)Ϛ;۽Ya05#¼WG0z5SCO!]f֏>jfhe?9olE~g"1[z[av]b|f3S:Cq#d19e*JLlA0t. fL0f7ݽq,VB9ޱVyݩB= &〜nbLCח =w;&A\KEyKTvw0*` qr꼥`gSs Y^4E16JRҿObdqEya:(7钟1lw Bll wlq,EѵWm2AV Z. )G|x`lN֢M:G:x38m;~W 0\tVKr3N`ںM=X >yGXNl"~0U„;bNSz n';mf.yo?=Jԩ .nv~5ɹ+pZ߫%Js8ksα4y&B݉\kOw~W/S03:;XNj"/ބ/@S1sD!W<= %xh!+:8prw^mvK#OUrAڐ`͉X͌ك [&!Ϸllr(5ߡ=G0ԡoJʀ"tiRMvx\# t\im6V ]ڜ죑Yiaꑙ@KԴ+W E5"jak!#U^ybU¹ R233}l4vŗɠTkTpt\M6<݅H.& Jsyts8:v<I|pX{*WBIpm pb)w(m{fw8Zj. *t+m]w/DZeg[.+x|ux0PPk_u'&`8/v@'P5) *+.Ph/7PTY8S٘'IY⼎cr@.~F(41׋9d63kX6XdwlLc_I'-kNPܒV3'?_w7މG']MRXS+s\s(r A"i7xYLkMKid#AWF O2H'0@E#H2w(]Sv4fխçgNRȜ W%le:Tx/lOj\k+v%cR6B1rLH'v}؍A0fpR5PF%q5whw h*@nm>ot6V#PDJSw_!\Z̪˘Y9<{Rζg`jɯNKN Ƃ*/?)!Ӟ,2Us<_j.U *!S-ӳq#0b+1FlW+@ J#Wt|UXjO;ne/#wcѼ]n˘%!( =g\$yA,; !'X]j3q\u~IuiZoK:tx>9FV.,MՊJq'E7]9jpH &QlLypRlv{2;i@LWqu,CPo{pƘUtgDt7<84Ԭn&ȡr ^~&FR0MIeF6_hӔ[) 헌kJorZOML3_Q;\$uA;%\ TH;Qú`g$2ɍ&P*̸,ij_%κib@44KY #_ӀrAz>'y2+]Ϲ͡iDޙtjZAӚ4<w,`|&&=Q=1ݫIWіeK֘hT[/k`cK2i#5a`b7[Tp'FXƉ$Oo!ilp!LҖ5ОPѢA* Fiop댛v%KiBv6TNvț9F6:\r:!U5^*/ UK]Ҟ5[0Vn}yTwv'gnvUA$Gڥă |+i`$)-6,[y*ҷfs.2|?njY::Nz:5LIG F]Os2'K55w)Yy~A{Hлed\U(-Ł2ϻdӧ@'mn+>.Y.No1ǿ.c%1Փ0zlvLo4faE5Kl˦m7R%/ewD>{[H9/5'Q*Őe]uT'=#G9NV#TGKv Ls]UǬ[&PiRPMz2i˳x+@HG# 1ƋktH,΂ͦoWxDnWx[M;Ww#B sU`ÞDXaɄ Pxosl8W %X%p!<`W |<ä.4yk޾sc!IdHy*/#ʭ&W_2n wj`|VW DO5Z/Ȝ*iCoa*yy8b7`Šz W䅗Iɮ@RSK7Fʚ4/B-'ĉq-Н?gKAtI.K^WDAw'<afu>,g;z  &8;VT̙5Zg;'4Ӟ]i:٘߉dȠ (ӎY@ڞh4?kDݿb/_h.2Wbt͊ KHq Cibd4^Z>Yr;p>d٤6CsAI#kYLChؘif>֟!eWh+`r YOzW (ENlFnPjND|F36TZ m0#lZ1R_hOJ DiT$os}Ϋ C$JB"hs٬;F v;=m%u$FY#\d$lq9@mMZRR6i~P8аr٠x_ K}I[ΘT5Y3n!BE;idu!w[L.d-3€`R"4fFF5qZt! 8*_ӍZ#OX,.DbPnOAMG:Th\-*2[oꪉ<BsSԺ.Qze)J[* 2N7s%]{C!/p_T|_FHzz^u-Ybssqno4O d,-y0%etn1]ʲ->̓FFjE:Fn*yPHJ[qk@ eJ24F #q<`;r>$</%{J 3?4(R7ԥܢ;Z3ਜl"rQDs>!C62B^/)UJaR;iXZ1J] 2L;l9< >"Mk#gdfUH@8u?'|+bewIEz/YƛǨd>ɪqNQ>9$í0` }\^ܙh+!*.[/) SJK8laϩ A9* LG2,{>Ma/]:=25baFOr뮘-ca0| G Jߢ)vZE] /nJ=ٿN 5kү2hnd3萋{5V =LeuyӲ#SQKHBՌn[W\sq9DGQ۽ ( W~ִf)gP^w&mRa{pNmUQ_{C6|׺57Fn/䥗eF%~vb+Ze$q{b%Rn0@ZբZ 䙋ci`O:@]_&t'oj٪!"0ZIȔuEVQq>"P/`eqd{hMGaP+NʇOm 7ט R""m>Q h$lXؔ IDAT;IDNlOC8\b7ȽM!>/ 1!mV3Rو f D7P3"{5׷OA3}rW~>矽{X$_k5SJ>ac6lnwgz$3>f>BjNbQM):_^lBs6+L}WfY 慵=US M8h-#1· Ө.4'u?D*-{?g}D_i2WYmІK=:`ӱm?bBn0݌D92 ͘bbS,2ꎞ:LB7^e6YBRdY 9I̥3`!LW\{U32_k,R۽[Fd .ŕz.^KE UG-e!loƗ lwd_JENNi=izKj\TF0Bmr;yn3ݦ UbDqB;;AFA a/"hoΓI4-c2U00)_͂YL&@q#3pu:q 4yw_#w^F4'4mf-: k) \D1O!X{^xµ!/}2PuXԫDۇL0O[Tn5:ۙxlC|AЬ6 M X‚'!C8 o+5Dќ0j5w~ML#g@? Ji PҰȸj݀wMq7O.Z&kx+`մŏ)7{Iֶ:G c m-*@j @ukX Ͼ,긼nv2x0/l~sEތ3ul>+iN{+>$(Sb &Uh=ҐBÐ [5C^ VO·QD$Eh*ZF4kmˎmR2/. =E\TSeF#QSswXXT޽ӡOx` I{6m5X kQܦ}yl7;nˠب#f,;6 "x-E>""UP'-D*eUjrѦ0Hrx 5 w݂=4qG$ڱnbpui3 hyb|zUȌdWngVtIєR  $4X+rkaH@ԈL0_p5őϷL+rh"u1 hvu5Umk?5Y2ۺB9fip 6# jwz!Bf >8LZxOsbc&"@GMWk l BމUfO "2؃ ,ƕBVH2V"(i!B Ofw<=K_ibJ{\iU<8.xofT#Cm㢟 X^Hw&ٵ q3Olǣa# HMq3+Em9xiFFg(TLaP,󦮄8O\H̱#MEǕqBwTwkSl8t"r0$LU7CLi=m;>Y̬1^"i6Qw;J {ᩰVƀZI=0;}b}}-[[݉CPdmL7-~>޽~ЀPB,d ,3 HŒvc/dF؆|Āqp!6 e%ԒzzOo9{}nK8=TZjU(lR%]bSβxL{ݥU=q&yyNN@d*^MTVH w&jbƝx~m ݍˠSGr0¹䳢]:8%yݩlB!g##eXIIUzMt9FnsAvi8Ɠb8cg#4}衋o;E԰[ 9ŒBI9x|i6"v9"7@lI>5N4Wv8+Qٌ.E\lC.nx֧1klVPZn1P@w{/I\w("xhԪA%i -C/3*%|sPlD89LYZrjQ]+qSL>,: Ӯ Cג4hAz6fKKt4S3<BY@p-1q!W))2H g;l;VYUHR'X.%݀֜b""eTR>NQ ޢ){tbϤѹ&QTZ`6/VOs%HcFGtan'qtT1#3R< g ccfLCaV>zc G֨ HTxG;R VX䂔](3;M,>Op/oϼ~nR,ϙϼqz*1Cum_ilJH|\dS=\A"fUs6&1O" A&QĤ@}Dd[t!J-uZ4ʃ`Ө+8}Ut.6  =0|1J _$l >FhIvC]ÖBi̼awMfD댘p$,)l.q6%TfL;’L#aw̉,p.;~Qb"n2Ҙ׻K:7͒>$d-;oY)WSm{sl'L| _e*K@Ґ93(gs2@CRߥs5g&o 7Ώ5pl'&QY봃rAR4s nQ\hjt:UM'Mi sR MMɆ2Z*6\!6^Z]Y}HFftO͵š]6 vLuTaJ@R?Uj+i@N:5!2)޴#Pbcd{3 i t-Z`ȶu@JG/f'fe#|#Ifi؝!n 928)!Ҍ:D12kbJ9ͻ~!=d0]ϰ !>>,bBf:SF1LL88zŋyoTe0*2DPqA#-)qH8S#BܧY~t=y| P3 `>yu]VcFT#n≭op3V==>D[Sa!OkldIatnGY K6Ӹ\c&_5OhJ&VUE憮fBsJkQ"U\;" W#tTZ!el^X[|-ij!QmSmKKQv&tk.2cL;+@8yIGkZy9LL<Bdu =C"L94|ۢgDGHs ~lRe { bwm6(3g?=Q1e92nN9s&LL+u?g,p~mk6Ѭ- jԵsd=Ol(M?CxĞ*Ez97k?ҁ +!|"W46͏xuz27Q U"1둘 Ƶau93>q-4-Y87>&֫ &uTq|FGص zXl9_ `Z;* .*BLcO[2UNUz>mdR[y3V3&Ej1qx3x:O?v lDsFIAdž+l+HHUɰV%w@)s*X45%J~+ܲ(%IN2bS3$:}Hy<9sD.u=9)Eڝw4KM9̜n^)ZIVG3Ͱ1!=p>v:#__t97ʦ38LFuƚJs=ܾ3rf4NCBy݆6?.k"T_.:IuOWKK:V`Yu md l\gT[.MNg3̛VOq]C ^IHIlP~qI J!g3eDd尾DS)kiI`L([@>嘿D$"|4$Ɋ%QMѢzBY: "dJD= "luxs H'0FD<}7KyIC7κqgF˾w((+cze5>7n5b'ͱHt2CWqFa3Ln 5 ֠3mݾآKQ3'^S1ШSiVF:U8EٷfC &TT0qzM^F $cC5]h_shںz#k&mmԢZMjơNPI%8N6g*YZw"ݩ=S!'j7j+9cP buU{S70KnRfB<8!b Ѹ;BmؘAl#| v O&ʙӊ6 /J!5LlL8H7du>#RУ}8/0:Oɐ &#Ls/ y&!.NƖڷ{2y])s.:$FF.dZv q Hja.uϠHǏCHF' {d%3q.2ePf@#NAcnB7KwO}>s܃r!gK `møΣ[uT'eè=t43 EīS>U޲cC>Ф[;5ump+;Fڢwb&W[Phh!U*#TgxA*D< Ɨ.3V<2V#<i}w+YbG7i(%2,Z`v;M9I!2$;nz QF9p"0JS{-`uAx9sYH[Jīւ:7TeSzs+--(fFZZ rYʿ4 P m5}(]IRl48('y㝪+Vq`Y VxyzZl\!\;0徟xZ IDATOzX35[IOO7* S KW4> ~$z1L Mn-7jQN  NJ~qD)=ʙA5WؿՊ+׌9%J5uF8Z|5#ofI|} 6nZ՞%hed "pΰL`#prE&s@]61VfPF FN0Zˋ{|Ȭ#SK^v|2$D{Su(l,},L?axhOSӛ\LE'V-茦ዂTs=WSh-_ 096WX :kM!irwSlJe!wQ 2wsjš,Y% /Yf'<h\eJ#6TgA7O;qK.Cz%r.#/ #7V cur1EE'mL$2o(Zfjm/Zy,"[b,rR[(K1#l<X]Ĝ;BzD6+ZMH"0Rz,d1ʣ5)ͺV2尉JU%&KѳNJb'xdz0p6Rșr1UAi`Vr5 嬬`*zO>.Y{*[ٿ% 71O~L-dIUwmXk3"1Jg֡U=1j#?'Ĕ=>gHTE5uSm"x^X&i(Y{ʘ \4 LY*kTݥmڠ"jD-5XZK=T.i(?ZY&r|`À!gItxe\^!ɦpM" DU$շ ߚ7K Q 1 '-|z&Fdl/׎ .ϖ?ǯh\jPIZ-”9&4koϼld,ѹ9q#+|:y[%%1(3 ȼ232fy h5o/Ǽ<Ȃ\ڨzx jL1hg6Ӯ]K}aHmԑpv>UUv f:zrlV+2鬊kT*ٔYC."H?*vX>T bU 5 `ւ5Uopp"[)=kFY.ݍ8Cݎ WޚRs PӋi^b(3,ƳFy\C[3IxT|ItƵ,~%ʶp4)SI`LL~Ǵ[{)"#2RDZ'f@ Xx˜ E4NI[K,ޥ̙,ag8(Q )[hH"B FʴٸTgٙ0G-67ݩ{IEXV J([=o cFg,w"g0$, d*l5⹅>n13=, R'VF9sSICEkYK*:%c0Yv½?ǜ=ƮiS!+9%ӃGu#+o:;%)!EhKĎjN8[ 4 iUl̅tVu--*t65( UQ:TwJZBN78]rlaY{IbINS8!@"D{E)HZXOSc6ǯl_Ͱ?A^j5b W +K<<튢S#gN c>m`''9Q*d է{DSV4S)G H[8vݹ2,/P6(s;lxC%/06WxIķR^򾧅i"~UC>T#6~2wsbSCn>gatFbPpɞ!\礨Or smfWghEpɐi*XۺOA8-7/hIt[dH1]uT>u;P-EWAO>g$5*mZ m/(ML-*H4[e0B'x+}dO2*~& 2 #$28 P.1:NAUZ`ьf5&i9Oe{BFUr8U4Ǖˎ{ #Az>Dq̠ę#X SyfF1%~9-:;2lH$Œt'BH1$ˆ>xCr38lG^'=_Ƌ{2j@$LrP΀O$y]MkXj B>G-V+Zhl>S*BhrACu^}k :E/b'յsSHD RkM9lz}7iUrqQ'm҃ʳ ZHE2[]SW\ "Z)U*礇 =oQOnK$H1-4h)w6V]*_B*VoeC2Rֽi ( IZҰH$d*01ʚkyOA/)x*M U, *8 DT C̛ He|JC [ͤP^BPxȞI˜YZ,x%I ю0?:)w?~>e|dG[;mȦ upiN|-{[y+Rk@\gReDӌAi N#=|SwN/cb,ǵ-M|frIdŖEiS E*7΂-_fTK[|.o"S[+˾p}l6 W冰 7 7denrBv4bh_F[jJg4/\H9,P'7,V^֌_C+LwS)"rA¥m.^M`q7WSqG̫t~Wk eQ<))R\X5z^ز\hh#\K>i4*$`=G yJ.@S:] U}2Yh#ߋhnwY,uUMbf9?Zyf3kPDBE3z`\,+5Hlg92) >F]UOS,Z9H-`d2(2SӼ-gl~[ݱЗ0k' $Bno0)bGpWwsG! AǗv'pĐLO!Iz=ՔwoPl+Ԥpn# eP/Zp/SjOZZrb |╩s 0c8φu7{1G|A:ISt6JjuP֮4Fy8WS*9lV2T_B9|V0zE]J<ѹͬZ8,oP)Mf6ԐNӅ ]jE])ЗJiѪ7z a`z%ͺ!6!Ȏ^#?VePPkIيa8;13eR,+a ϋkGհHAH$5M@u<?1V̉!IX3VU2'FD2SB"wq]_H)8r;ǂkfjRf56 h}+ю Zl(yx𬏟 @U{Ji&WNo8 5ajt[-lʯ''}>»>(czCpɠQd1'Ӌg;lGάj%lIǦEEh]F$Ug~2?'0;z%"y2 &OQq⨋.u}Ys ]֫|r@ۋ4d>Gh#K*pp۱n&Rm/Y3SM8g:9Qk5skP:eu)v]Pa/KȠLԡwݼf]ץ8-w-`%.2rƻ3ZHK:_d]*Kp#-Յ^qGL~O^]C+ liU4=lGBMn. kN(G@k5l7KYV5"N^NjEXĪLKŹHuI TXp@ͳԶmSw.Xz'FMz.Z2Sr=ZZͺ>t1Ke6!rGcrnI3]Yo|`}i&򈔰f)SHXy1,.KPk[VWmo569jwKUBa~'e.˷ЏE"ZfaesϹ'CIBPׇp ST&Ffd,LӼ뗳~w.uxD{{eP,- DLao0_~|9c> j5h,gdTdIBau][ۗ|^sOf MP0€aiՆP&mL X%aYO-'A== FT_5|h ؆uJD3J5K"=F%>ouL~3V*Z֖$׭ )`kA~Mö l·a9g&2ƪ&m(.ruD1C4A&!Vjty+D*Šr(Oq0UM:11! Yz rb.sv%'U]]ev [q0 |u|u.3NVjbv(%RAJ%YjnH/С mϰcсч =rIF볉Y.:%%T :m8u}HݢK}>|l{Rй ݊y ? $ɤdU[k 09=$sm^ƻoK+Wbj=ZK7_*yB~Aƻ̛D>^KZ8貇'$i`l>``Xɇ& 4[ |(C +-ć xTfj>QǝdF5ȯ$C$2hv>: Z&hZULz.V`:z\ifj)Ds6ǰlb>K縿yV"wNO(VfW~VVbsⲾrwsdRTJ~BV{ +?dy7t7^}y5,,ХUa:< `M.ʪo^u[V:d12KRF9,^;,:qj7Ѓ;djEպQ,)I٧^ enWu1qĩKiF]ߥRO ]>owcHE5N\Mg7˹#J yKmkrI?V&1jw"y{;׼|qLOy|Xъ7|0PW |鶉Ļ,Z78x"5y!Ĥ9(6FʙV٩h2@Z"򚺗QIAj^R#]SA Ц3Ew5xVV41o߮DSN}ɊvdMvL|S">9;w_qB&+1Mae A?kp5GMM?k[D!,T"UE4jSEOo"&3M7pRִeړZ"1Z)7ksrqLBB:C7r:^jC E`hj8r8ĢBl),>_7Io ';XIᡟi{L`8,xQ,򷾨1N5⌠* m=gt8hM7BJ1[۠qJ) _8,d$ m15M`̉StrOvPC 4;ywriە$ɔ@ l #5ЭyGX3Ġ(K;96_$-dYN˖>Q@]D|[XuǬR|3Ӕk0-oacm !r$lSWJ(:#X{wO^yWk [+e.xMT2noeMRr@| ;c:D@Gku%"!|f/d)\]7)V #Q>̰k1+$ N.;5Mzdtg[*RB`wSMEtDЛqzPO'POG Z|pmf^; @}b4^Kc^EU.'hF+[k6:FԤ렢 IDATNOU[vgd@(ou<\O4j$3lZ0G;h+a=)X #(0_ftWxo֑Ho%HPlܯ.;/gbwJ:.5YMdy vZ`ISK6Mo8sI*]±ܬBVlH\ KŒN|;-z>  q* ;OZƚ.`Vkڕ& VJ3Pɦf@:Lw5TF"Y{ Y*&BOgA-. i-\m-k 0xxp+c̀Ta#G B } 䖔Κjw5<,#OK:.JDɣ1v`}VQaH 23s'ۡ4 23Mݬqp2чc!tti$Dzчap"gcamB_ 3M_ɒ[H+]Cruٔ8O'R}'/4V5 "^oe sfS=Xf].aئFI`>.L! Qe|vM/:w"_d5N/ǯMGVZ|x0ѣ6T&aWW~'oE.MřoCE<*6'CN3p:9w:v=U%R11 A}K9e`DJFSB.)y"v[0lu(<&2pKlkQP~"p]`j*<%JU)Ӽ]J>B?^m-- o,%YpnAc)~wІ6SrܔFz0mI7 8c SqlEpE ބfS9YCPhWnRY)אS+ٸ~&jN2R0N)ZZZ5V cMJW4mVx7p3JdNSZ=!q6bV?; ,3T [Qd>i;tS7h=-Z~] ֐(`qȶ2,NC`/M :k y9U5JB]FAM@QmjI2+q'>BmY"c:"ѩldÀujH cV02a>[{B() fC>J(wCIN%P"Pˈ T^HR>u/DQR`ͫ\o{ 33;-ӛ%t|-7}/R}Op^G嵂ʽmа\fj61WN UhQ8ȶ'Ƣ͓9TU% ҈78C fU7)8R2 7)ֲ՝\E I*Ȍ֊b_flv lA_:f=_}UfU KtZIeI2[bP"Fpc؃dig|' +eI)QЩ*V EPJ^ҧ'YXAVD*<gx%!N9HnRU!ipOgF PkX_1\;'vS|YgS'>!mor'Ќ}=f3yՒTSyΆPnv{7yQz^aهjA3SYT1;S&#"1 ,)VE<'_ x@nUoS4_OrhuD9S]D% MAC(gYͤӗbʬ &52)B#SoRR&>2p4lE#Nԡ$x!%JDe*W:PTO%d "S_إԕh[x-NO}w9ZbU&i-_NFFkȇ콹%xg,i-D pua* qBB,3/" >g\ }gEM`= %d'V(ƕ|Rc)A`rQ +2VCdOljT[Qi-T7ܜz(ъG4QV9%E}&~S_ ܊Ple̾.E*q 40/ !ѭq{TJa#I}$UWXᶈ8c**QG ˀ&dƍtwKædyJC -B>)+#0%s-v}" 84J3\O]lc"XW#i{;ppg K7_{ڥAy<VL^5n< 2MY2[˲p!VfԳm̻|?u~R-0_cV{p%uuMd_o~~>g=z^IR@ b{24F zϩ–77/nr곞Ϟg'U>l@0LTտi6THۋ᧿}#o}'s[Yo>@-5_>AR@*5FUΓXg~$3tO]t3YYqVEF u׸VVrf*mjXRe@Vа\' d˭UWœf$u1϶)u0#,t&,!U E Dęzhd5 tExCZ 2"+RE rD@G4NIbcGDetKj""*YG[ݺzd^ wg]5f1DUA 6=0PxwqI`-O13r-]__ܱsU)CI2Fmx^|dv=3ml;MΟcg׽B% `W5wkEP嵂pA,aHePmW/ =Ows?oOom5#2-g q7JULn~W_?o7:>[!o]9I6 罪)UT5\0Z ,@TSukVG oDlY i|x'_($SM^wtDY:4.sʪ5)Ń:L7ϰj֭aɁaV!9D`0g ꗘʑY) ʯ16 XTl;eЄ2A5_Z,)(uHoT įI6J)|#iJRZXI'DvCqk81_,\`,26黽m,{0+z2H=S3 [a2aX8n[E.QvȟTnakn/OZYg 2BVPLaJ;|k2M O5뷶N[GKvOad~hq`aZTp_T[صŽ[ 6ZN<9U/2ዻGYZ}Wf2msx:}60SCzZKոn,NGK&oAAop 1E,:ݥ*iѩ":Q OA ,w|ĸ`A J0_z/rN_ͺ-1ۏ)atɈT_ Z P0 d af*jMzfڜrԞ+zqZힳ ,"ZCelj(Krڦa.殫aקG[7ݭ0:>Ccqzz)8Ŵ̦؆ &M[-ztX pʄUc-hygpII#nZp|ė?T[fϊ팙 f}e,!ê8Qɼ !3ںu8]kEڇc7_o?KK_x~S_rx2{k򊷿m{W۞ Nfn/?|yֿx_W}s{_E?YxsY?m?K [o-Vth^jyg׿g{ۻƘe𵃭G8Z>~e(|~/|r<[[VSƯ?k_;ϸtt=~ >Evz=_pk>ɯ88^:v <|K\&ogZ r͏>7=g3Nb/;S?u=_z_Yu4_{CU/G4 _jY:}K*sï8<^Jcż^{>ۄ?/]֗E\ŷ/<^`wϾ[_~oEy?~+U[Y {.gw+7دGo-+ ~5*aU x-8A!k)< "ӊ*D@"ÄE>V+kX7QiF#k^Sx񌧤j I=iRĴAs2kBU*-@ @3cGhdܚVWZ5ܭ9 @Z`;M#w(Ó:X$qؚu; rUeU0zEG;RS j!J1; z&z:9]SYil]()0wx. 'Af_3 fFzfhq)Ĭ`-Ė*3{҇`0pSӷޯ?ϿO?W~os>})'{\g<_˟JW};^}/+o^C9ϼ_~3tG_حz+._Yޙ%o/я}ӯo{O|nG_w?|~;CŌЯ~3::oz=/{'ooҟ(9O/_|7;yS~ʅrd~ϽO_}#uo~kSosw^go{ޗ_xmo0Wwo9ԋ7r~0Wwf^+Es|#NMK::GVܐ1ؐlepHc]o$mSj-ARF-evA$tQNO>z%%Nb¥_gQU%6xm#VtqBc:\I(X;>^4Oq' Hd ;erm!i8;&OXd.=.05f g~lX,t<&Nʗ&wu.6$+aYb5x\gUCڝ <\fEH_~~󞎏q0I)31ccQ1c_L&o j 7 .z5pϽOާ7|]wRWol]Ͼ ǫ17v^y?m=D||~7?O o=OqhzQC"ӊ?#-eogQ܉#sft: 7wYcl]Yolb} 6!@H FHK3U.D{2#FDfU7u wTٕg>7? Gz r,9#h-+W]vχr5Ss)V']>|Ց"LسuE?s?|G۵K'vj; 7?u?89//MXX;9}daFUw ߹e5] /<1G0ΡcOu~[??qta_|ۯ_q9uw}cyan>` IBb51J+(ưȎ 9o\{ٻk/g|ƮS;COulsc( >wGvXE(>bD5]x`Dwgjgx+bPpw%Z&vo[kЮsr%22'&sc;f{=ft;/(W.U>kuW':q_{ fڠ2qx~J K tc&- 6JYI& ֏t#P4#Ɓ8L( ]r~^6 7ޒ@}FB!EhhI7][hrYل`܈!-dVw0 p'Fš6C)hr5;@ NN#r$SgɻXEMIPKl DTN^-!u*G,l"33ޫ1y_ ߃7-!#jB2\Q5Lز:=\R3Y292IA^cguDYѨ)sA Z]Qn۞%fSxnzIUꯞgy\{ grf\Tle?#D¶|j XL{{uB_| 3nǶ^td~֑wQFvFZCV@Mּ"ن/J.{lTQL#FԚP2wMyJW_{ŷw<۳{ǫn0Mh(ofGx5'kO!MoYj&f]r7Es\,M|wXa$S~!Vin?1k$$BV13k FեzS3Nqh`FeFɕ /i\(&2rK6B7)gKpӆ[ ʡJxr{g\Y20Y'=g/J9G SY +'AeZN1짍3ފh|-p!ꓴ> \MΛ()A4df5g_C_ιFUL̎ uB [D^缎/eUE3S(\RfY!={FTjPͮ&RɎ=,YklDgL`MRl:Vcl{:ǜq|0,^,]aFuG|fWNR`8 /)cӏ7.x:?uV K 5˽#3g?[: k1 JDYߔ'$y7SYYEQQ|,*dkA $0x.ҬJtK2[^Z&(]եpb*mo\:F& w)d 3GhIp2EAz950_imq$^JS4@Telv[Fun1IUEeg؝ Q!(<ψ3dAa} pxCϨ=p 7Fz4< ȍ\z)%ھSaDUPVW_rc8.N ;#q"bZg 1Ռ+QtKp1BUnCB[ ߝ1zW\r{ܳ}}(<4uͭ={wͮiwiwe_<MT cf}sxL}_q}׿/}VQI%v|x[W^}ŭOyCʍ?xS8kž+-|lwm[u]/}/y By}7}Ͻ]`Ɨn~ԎwK?t޾|?r^wM/ݳ+Ͻt믺s7=L>ZJ)O8 o䰥/K?vQRsnywϮi_; wŅ=qk/=yn{9e] q7T_q>o3ߥJrhL/}Sܽ'5%߯(FՔ|7W_qzXqmSRdiV@AHśŕ)^g-J-Km҂,I+mhK t's&j>u۹Ž,10vD YPتARR(gSqS:Y(ZInqO\*hI,(=.m,WAyX^V3ØViHb.A5Es:aJ}`jK_Tf0/յ pmu_] 6766á5'JѝsWԽ#}y !1m3{LN`;a/RyO-=Q 1r%g^O]kz/a|k}ΥTw^zu綾O^yׯ??47O>OŦGeMLՙ7M[{ϧ^{K;m͗|c]UϻܽCf?|kO_^x?erp˽|Kr3(|[}|c}ϧ~Ӽ?Սo7N߹tdn_ĺ&ifin*5+oU9oˮ;8O_kzħp  _o_ɷwSW7?gkwO|\{¥8ED{y >yV'y!_ᬮ#W}3v/]}:G2Ͳ¯6VdL7t_LXM|5&q9)E.>m/m{:ǒp^f9ILt'#_͸Qq5 Q߬P$[:~ }v»0qDnk5m<ҘX{4<*ْqĚ̠-yj0_EŐvn[X@=0<^UCt$L"x{QF9p9pU5LĎs|8e' T%}K57z?qB)5fi0]#4bp5r&KzcPG G&!3Tr2oH9x4/ ̋=XY -hQMݟ9_nGmZi FzQ_g^t.|GӒ9f;uvf漲UGbS΁7?g^tʕnˇgfc xHXB7{D^sdqn[UeWN@t :k ]EʙcZ7Xs9aYvwVɥ`_]^.3fFv54*,؃ >ivT Ka2e>a}:pdRG=U(/rKUlv&ُ1XB1 [SqS9kK`@eU4ћ&f%I8I@eUY)pSaЧŇϓgfF`L5Fp#|-nUe(ޅ PmXg[ ؕ!+cM-'^"ײ6:MJ64{ -pZMJŸwŕ~zlW9jE4*R+>S'dY̦31@(?+A91Ա*vVu5׎y!_#rY0,o{p?nyclfEY"dž@Oƾ)NN!6y/mTjP CDM y߈>h)CːdDI(Q:5>ndl0LjV5ɤ}Fu$ sEV"@ 7Ww+ËnN6+CJ"..G(:U\ ۇņbL~i|&"bE\EtDG7DwPtFM+}dQLb<*$~M$@w'pei. {|C`}\ )~RyPͨFe&ʢrteߙbw/qsw'6RM_wSrIuuϽ[;xϕΏ_~bRp`[j A٧fӥ$9km Sԯ0v{W^|;?qդì&_efm:xkjκ_mQW^t;?@ΔԖZBRr^p%{,1fc xc e劚zpAzuBN"<v.[Q5AE׹JP䑝irt|PFc]O躚òs+|nݭ9k**;U5Q+“/-I1em =eXf\ة,* qƵqIc 5ڠ|ˋ?gBYn{?gf4ccE߰dU|Sl=9]^D5ٙLȖ.$9N-/e?ݟXZWbekGͣF bue5 ƫ=j*!ơD9(igYmzJ+cn Yc58\E ,@NtƏk5pAљ\1rHC8Qr?mLA8{ÁU(2BeO-5yK [["l0PfJ;2\Jr1CA]hQT߲wt0cYrHmoVWf,}`GK~r@T*=uk8?y ==PpMAP+GTU(Kr M(N ebaWuzx43S³{~0}*e1R oFaiԮrDYNTeʲyHOy~c0pdq2pўL&QgmYmN &/M_(ea$!GZȥbC&4UHAGnբ+!h,R'B;DPlH xL|HK]^3UM ~¡y2A#wqF|X+j Vt+wPi.fLBⶅے0 *.vuXg9-l#Ttn0ɛUmU{$jGx+]LtoU X`*Ɓp^=PޝP%*@x9“Me|G:$م>#JGTg%Pu·+fksJTI3"a>ƜoxDzd|)5XbǫCzq #3[.+D IQXOH}J6]|ME"TTyk{ѹ?l"_4B. ey@F HaDU3ĉ r,q Ul_2X,Knh>Wt`U$Zͤc^(-cLDÈ8 c0lm=nPdE֫S${MaX|$=OhOx}CfX4!jpNCV('Sse /Q@ܪ)ɮ?Q+冔i7jC8qSjmq^ۂw01*Yu S"7&XzwsZ#!+Z,14IƄ;[ .՘7JQ4/S,Ʊ1Ssw#K ,Qi3EWE~#iyCzmZ#ujoa!|IGr*]RV̾s"k~FfB*fMߎ(B|.%0椂*'K8cwm@G"QdWO2HKi1An5Nbֆ R3&|m-(&!twf5qĄ&$fA6 ɜ4&"o|_GDA* Bptf=;[f7zGY6L¼GX ,\J.U*;eQ:rXN.JMca+,F3_S6_b0=G# "tOc{35uov}:T?8T/ItE`+cMf6HDYQՃ'[5_7h)Yaˬc!?vFrF9R;=lEY"GsYxÈOň`w-!F0+Pvj&ʢS5pfZrFf_q N[x&HƆ+ !c؆IJBa\uQ8adu4chbtj0 3'l9ewș2pF ݀+/)klM%'wiAc|WhpZT/+͌L' zM64F^:pK/헱Fhh#VIYNڥrZF$2G=chONԑS:=e"7DץCifefx 2Q³~C9jMBiE'ɡl̢-=j Vhu3,jf2".G4OiRϬURVi#ƜR,!je7)bb%̢C=9sV樸V4b]L5w%NUvSeQDiPt P' IDAT܎*sjqHg:֚H]UfYo,ڝδG1׶{o^nZme(6g 7jC&7ZLJlalL$؉ Y̖#C2= $1rV h'p -Sjc!¬6G@_6AK8_>|V"Wdcie2FRPaBUNJ-t.*SHBd>]1 4Fƾc9O5 -R5AeESSLpRҌq|2O)\ IHS"ʰvW\C^ad"QAi_?k#h L'EqE@ O:;X1LkZS@Bh au2&5R*›7.ǽGL 1jFUݪVEp+nPCEg礼8u굕j=r-ᨺ,A+.Q g9}{H)tm?#D?rRw|?~p)a51ĘMn<!q6iț.k,Maba#|挎*0,Tl9cD1)q68ejJd6ƘB& :kj,006HNÜR#*LsJ&wG$]OV&yauڻ$-@3ȡF<ݥmCeG'ɴ+eJpSZ"rkhϺy`ﯷbh*u@,] úRfhYJ-Z@ rb!j veL([Y:e+Kz(4?t/N@i^;+R{ga+PTY˲rE¡F1IRMnس, /!VU"*=5EWmWxo'uth;a5&Gh3;տ#߹0 oy Ƨe^6jPd"hPfz8}Lsv-e[>mf[LtxW?˟ww>#>9/'eʣIL$$5 ^\.ZP2fi1"/7nDL`r 0a>t1 }Nʀp2<ЃؕpUQvʲ*NQEQ:.Q +y]nbw>H&-i2f^bg_Ziq]Y,uV"xۇ4:PוiOLcC?zi;l%A 'WҼ&}h<׀ uxJoeE.7~wY!B~w_zݧ]ymt>uu+Zgqeb\Q?a-kŀyTFП"k̀R;yL#{CR4u*y6ciY0NB_b *m| F(~2-P)我EL k?dXY+.D:/a݌,ѣX_']4d/[R#> !JM1e*jJm:=AD5HܪB-F*'TvECm RB@MRg#|0/[k82qsT0o†a򮠲*\YU|+ɯ#&~9n먷ebI&4LU a!B,@ ^X<^³v[̙|v`s |^p?o=/?dg<~›'Ҳ>v/ [?w_y[^|cYxʿ“TO&:>{03qg? +8ՉI銋덟? 7? ƣ&VEɵn&C^_ũLkfMvFW?Gq _Te[.XWV&Ou#629ϹdĞ҈&AY3To܂X!ԮʐOiXuJ WFΰ9LJN=\;p5!H9O]%.UNw- ~C`e˜R+6+/F?#@DySoWqbֲnZ`ׄG=kb TY6aF's\¡.ycxՔsLjaXqs~e]L/1iC1d|'uV:$ |' L`Whգ;Kka_Rẕ򊵛:쉈 O¹ʕUY.,F5R>X(NLS)0Q 2(z>TzeBbČ&5ӝxw?Kλ`+.o˯v-~e_ KG߹_a%~׿Oó,>0's޳׿i-v~%yΏ=^v͵[~vά_jg&x;y%X{֮.0SlP ;c۵~ޯ:UM`9Z{Nmy#\普侧=|g_o^óS<ӝۍ(,̡m6iR mfR9*Dњƿ`(qiA{3Uq5?)+a!O"gڱ Ygh1TQ]PHn@TRb  -1ZŰQ$ˋ60.]:%6x mѱEZ'j琲']*ʊXfi3f O5bWL?ROl`ej#br5˝iG.u");J=m1 WUҾgph@ PN&FA#^7q'>xoxͻfWOܲ3z|╷~k}1?- UTGV9pdnˡªWnaerT^[W^3w.7]o/]y'zJovs.?=_\;ϼ3ü fg]jX8$ wyÝg5 `H` M jgo}ɷ?KoW&J wy]g5Y2%6'z6FN7˪ SEfJEZ9 몒+ +6K͢L&J XNH|3. PǗ05aձpa.rg-5'#-MKtóh ڀ.@R]1Z\} *04$ڄ;8f 0w((\+ AUKWW=%'O%V_;ĎZ5k6-i9l @Ø$}ozwxїw,[?: v.Kn~7\ ٩XLpߑ=~+?{?KC_dsC(]+RVp϶ygzLsX7HHnyYHfL:J2 ݪ~n<:?|٧ }e"òDoff/`)5G%)ۥY & uq=DN&fGS*34p !`kKEbɂD )M0]@4ŏkEh`A$jpVf(l?n9L% DiMxe\򨭱raSk@ vz|tQ803{x*q!:KTbȑl莓 vI! EDz %3oXer YүL,ۥ EZ8ysl| jp_^e劢(UEQt9a]ɣʂLV\OYbv'&H!X `,Hd*[{Υ޹Ϻ[{,s}⊯|\˵DZ@A0 Y%vPS?x[/<<%ؑ|\c0DδFGPvy@ZVmm(Pʰ>rB{omS{z_tѷKV7:[7X^"GC|>ke h**-iV1x.sm0!8Xڐx,5 G\gtaʝbeMc/4DOY!(>,ScqU$9\K0K@E\lbeǗ`SphaԂu$7Bil*g,LApq]8vp$:ubk&.Sg8 ֥^>Rdb Pd3O 23աRY1 'aıѾKšBPy#}L( Y[t otua֬X.{ع @|L@/N!z6bmetet#{8q،7]p9?Q.9ozT@#3g?2=x|z̵j94gySw|''^^=v3F 6'f^g*Ȗ_3A(ϙqiS3 +k.=Dx-N/Lh%),nsNkfm4>-J X)"bdR T~8.zeZcA,Họ⒒d U?F XF5ېk`XV94l,n$'\d,(C\P 6h/a1<0{dDs%˙#3JQգ3%v8r XoZp1x3'=*v;2&Ae *a3ϕ)*2 ;82Ó<I^<+yO{PWПJ+ZT"B %uc*~rr(;013L23t~|;>e IBL=̋8!<g`b8.xMssEK {ooXDjBi$E'2:ɄhŖU*rObw恵[^|޽9'&>K~zrm37}n֕ Qhuʺn J%:mҭ]뗗-OBO–Saaɩq{͇N|ϩwϻ3?t7TZ¸U)|_qсwKCS'yg;CXZ4Hߗ8Dr \qсu_Ï<˷?,?_rޡN9|YGtW?S?I%%P7B0Jjfmd!"5fX$ I$+ΓGTBuV]cN6Ҙ5aŝT&79X"XX&$hNʠ~$gĜf+ Kt"n-46%&2gO!*n;mpǗ2'1SHUţؓhBX\)`8> &fv fv <.l[|2XrAetKLp9b\Wנ6C|aS!ՕD)N VW1LM5hq ?$ֲUM7SxADEQ\AT9*aY:#`Y?Yh5+V5&6Q:iZ d/CE0[7gӫ[Zx |O|K/p֞w鶿ӇϾa:e|ןڭ +&uo?yws?Nݗ.k&K$6̍s'.f3mcO۵)+.:gwҕnp-~ f6~Opݑ-S>[P5Gn B^cFt&~MEB9ōjI/-ZSf'0h-Z8.LiE>3Z4^$c :c1YTl8H[eʍ jQ %B'X 2O3&4k,vF4MqJqXE\ }36IǗ}٘F-~%^[)M4dk^Q hZB46Y 'FY ¹AGRg W:c?iyuTPb$(IB˴Ɛ5 |.9n xua}C5t(HP%ؑ ࠴QOp`@DpN*䜃C:5WbS*/Ɂ~ >zh︣zZk5&qpFWRKYEƷ:Om_Zf IƑ48טv"}ƘC| L9n=a]cc*=kM5$Uq6eL5q;h2L/9&ubsI95!ԟj:z)Pj;3M[bh t()WԼpz܉rYǦi&S)d c ݣehA3$AC|bXe{eGGKC8kY bdq}ii IFұBIiB3t§ ˡ@ _gW{ڭ13N ʡPV*T*'@\AT0N^sk#F<b8İFm%C/nyCc#čKa9Q3D IDATr9(*#|bEqHXAGw"_4(IetG #ϚE9MAJ-eMe22 Y9ݦ-yvai{rm\lqe ޘr:8!&z  ?bg[ wRm)Йr*VWm)Bi5"fgh9?Ձ<~4|l+E] ^ g"H4̙|2D;Zs2a?BZr{MyE~#͢'+Q I 2Ӹa䖫Xypʘ ]U)StFɴe0bE)6$r9 *Q䇘eQ,͜vh8eU3g4IQrPB518i;q1)9ڇ7$;0 3Wr]A.* 0,oQzD#o)W4Qڲ dk/X0+ *!s { QڄV6['0R|縱 ─lncc&c9uS;䔙EY0؉?-ȘY~/PZ -&Glj_= dN$jH)-\TcHp8:6Jһ4S5e1[PcE_h8 ð#d*|bss4ՄTD͡%m 1%-fZkG#`VLY ,%B);~^+~Y9'/lI1>RѪq,1,^FK9Ĵ7$ a]͓}:6z r03ȥU*9T ¡I4^ kHҀwtȁ^+Fc,a{>;B5,T{")i48̴r"gб2+1|// NCV\ »W_ CnU'kO:_bAqE6N<0LALg&l VQae $<ԕ+e|,!=q֓H`\fCȬZ̒ND6k, !-ڱvnp\ɲJ!+($9AbjƳ}1A@,ONQ vV;H5y^~,Jj!ht#O~_sa[J,Eds;5 Haܨ C,TB%č]! 0YC};U=bnNu#[ajȈOb)ƈ`V7U,#@.d Uz\I̓gAF2v$b67,YJNe'|'H #wIr V60 AVAg8x2P#w#lW#I)L^pޣi1"-eRc!u֢vnu2=-D+OqX"cw dDyLAV8Ȱ#;OqRHM@KҰv9͠|t`ik,DhΠpn9|8~CiF0F0 0D؈^"f܄ o_șZlLYf[µ)G3i0-+:R"B$kWcȭ9+i(Lsg `%\6 Utk5H4 LW氅(hoxX%@"Yre8B5M~iŭ|bů<<ŗ 6E-;'L0`k`AiI),A8e`BI[]'ᤫgU^2K >Q^Bi0԰)m1$gXV{֓%zq!=>밪]ώc=#DSnfg5QjZVrYn ?\r\WVZ ZGb6vi1 s~||y'glfu1"X2agI׆mX5pé4EjAF<8mIyEZn:41~ Q+&̧l2%na>4"4dΑitȵM}"Ek!Y),%30#ň S١:$TL:._ fF9F$گ.&u˭5)ڷ"G!4MIip **3Ľ6z3n}>YJ/6 h>-%s~aJ L"#$cݘȱw C=ibA$81xUZd!鉤R͜XLj q0@5FЯxP ;zjt1EQ2 j P+PE0!HJ)jusO@2!F0caY+_K/c%lXBo,l H,ذ2 +@l@b;lσyo<=T_dm7}ϩʌȈ:+lΫ=F2j# ^v /By"eQN Q9u*FŁ=n5@Ka],٪' oދ~tF0zS>*)19FodD1 U]y9Oct¹QgZ~aߕ ۂҶj ^9 :f_P1q?*Vnyw*O]rE[gMd1H1}VkPˮg W}+NRcYWy&OjY# 3ܴr]ۦo=Kgy\݌5O1hmhl0E׫\ӕn*e.0"rAުu+N'70Z7/ &MsDK}\G}|={6|*g{:bf]DX~[x;>/z~5D4JOJrGOzJ^gH(E|$ĀtM Sz_i$S$?_qΚvRagi xxRY9I"%>}Ա"84V;CS/A)!tfEjZMH]:D턋hEbEnW]b\h{UOtq!%f@f[R"n<'BBجF/ǿ8i7s7`A;xu#w\;SsQ'D|<0>#S{#^aRΧ|m})}.[YB#\Khi#{_ǻjfc{; &x{T88 >DYN_//?/(ZPw3;HuW_|wb?||+ᗿO49|ɣ"4G`+Y7#סVb-2&#D$HcύN/ RY- 7< ;{]D/(A΍RsWWazX$O6!d+v/3M]O3VGȢ>1b9x]v{j].syakIǤgeWjVKܫKx&5[>o1d"ݦb x}#eoM7(c #d_LF٥ѿ.zYq}i6–3SdsN.C y$Z[MZnǛr}QKѝ~^k_||߈l[D"}ڝb͢Ptso>C' r"M"S);h~N@)?f,ʤEqMe^زy\kת#`2Ky2(pb/5YuSM<M"!Ke\n%|ڕt2Z~o*eNLo*Bz%V)NGF_=/IUNrꋳ>[䋻|y=/G4l&#IFSIom5B FѣSneqܡ>}Q9mr-.v9T!P2PpaMrpT/mm3DTOy*w˫wWdP:A4\]rHJj0V3AAzr,S&0Xe3e+D3son)]%>gŷj@{*3 8B#H:r $NZF&1'V!~ZY&~nh0k_͗J1nEf*]::Q:꓍8 z]8aYVXwt2.;A @ѷ..mS lLYn," \0W⻨h# 37|=#1~)D'6 ئ)4n|*Ta#^q.U6!Wiwe1D!B'n2' * |}J7mՇUp䦷UeؔTJ]jzoq)scP(T:ѫ36N8m~۷m{ r6 C^p]B*$OV,`&CL X\C/M3]UR57݌q &u6(Qcx~{uq[L6ߓSFŢXҶ6c]>M=NCQ?Lpj5q,('O$}rE˲ "S6DM4M3-2TU⤵!YԃLJ.B\OgrgZ~ ǎ,>VGmkOQY$+fܭdpӯ)69au&lʴjfDM 18r!bKQNe[,үXx}ۋ>lڑ>=5YI\N'qoϽ `]wؔJS}\T-So dQ4#j3Lv x~ *z~E€F{>[r#M "wYW`O;q;/ȩ7/T߯c͋zr/ 's"pIǦa&9\f1RI#"Y 13> L>v$c?5VCĈb9TrJv\60׬{'%NyqZ>K+4b3.n8;cNGrePHҴGqn]Z "{+ڝK_*E`_cO=I` 1eaGv C.@Oko4 _k}d˨iTU nW'rܔB}GsD*mpRxgeY6(O}@q6l6fY-, ^),q~C{sNFBI@ӷ;$/XNk;=1j {x(bppNps@?^ыSF"?_7iRp ~#ɯ <9ASQsuFH>ި\iEW(Il&x{j.Pk$5aA +xBJ5_ۧI"W`FlPcQO>uqBʉp9iiwA3KB<|%m}.ҍcgr',YP?=ƾe\.pF6B^@;;sF1t/Zy?8Z4Ĝɑ/CcomÃUIDATp#$$4>Ȫ?Geg*sP;3\TnRH !t>,߶ղގW1-\M1R*COVRK1~oooww^d)Xth܂}HtukS)-U%4$L=}hmWe%:fW4l?.,{ܙ A(=x?:~Q \(X9.U]#nf؋~z5C xr7L}v_AWpuJ^[(8o,5k4)L}-*0jwoZ* X"?߂ sD)VO4\26?HB6,rϯo~K'Y5q痔$HDcͥhXz1u@' z,q,Ӽ GoB֓=mg4wJ}/I(ݝ3_ W,}~[{}٨/[UoֿCYv<%8{by0x"Sw2G9cbcHub!EC͆G{.cJQiQtzD&aƝq 6# we|R"]?;W ;Oy2@MM.s=ϲ,XzQq_eEw^Ed8,Q`T"F^Nv=;ܽim yOS pfԖB&X`VR?C< G'9_=Le7 `w@E w}(e/ulr&* h-H|a0\e4kSl5ux<)QHzWW~0c9/ƼQ,/UƵ;!/~BgP:tXg@Ghql>QXg* :5ua9r'FHO8JuN2N}Iʘ c{bꐴkip%cW:Ct]Oܝ"Mϐ [0Ȩ|MvA\Iꉃ2@b{Ok"2Ь yzI-ċ B`"+vBNÊ[f." <ݕ$2ψBi̵{Z_p>oxrv@'[N:2]u3[JNt'-t: F5;٘#R`1 !U=԰!=O}\whGrSa-^,=ByUS/!V'd525ʮgzPL=YǨ'Kx^)ateKZ"ƪn}>a @s%T}Ҹ`Tr|h-TfvXOdU^3M̂ z|~% &}%~ )jw[5Z$/9VfMq_m=3Y-3#fZ0UR$' EX5F8iX "쬪W~+}?jҞߝ} _} NUO'S-"kD `݋ZԱ-qªB*'d)&_1,d*5faw k#J4XWIv4[調Y:'UK&J_֎SݍOQ/se Xl.bOXkxi^;q< ʮQ~W'@u1.Z:8b~꠭nf0-K@џXIfՄ)Λp_2"ޏֳmp+>}z$9ڡ?eǧɓ5 &ad+Q8\2s5G{.C$ǠM;~ëouH` +훉ݱܯO= R\[@iP&c&iW,(! > p7, ؗč{R%J.`,O"p:"T$U_=Hhg QvhΤӚJhy_`Ewa0ZmPv5|w1nG3Fxʛn44SR$jM> MyAҲ.q|.7XNm ]/.SU.W@P, >H#2._Eᦷ8An$ڍ,7@1ҡ`Cp0AYB.&}dhb$.WghLyPY/be"+ݤ鮬 "f.*l4іKFpȯ%o ]ah$ pVN!]ERxP; d8I)4ۘO.'XmE#Ħ>*FT@x)Sʅ& "6  ڲ)Niq):Kt]XUt[}Tڻtur/0= Ii V"mvY 'i{ t4c4 ٭H" nTS[L.h~j]uQ:G+i?UOڄNNfV1>c*ʫ;H C$+Ek%//tg&$v zBS)8Bt5:@HDJfGLCX0 5`Ԕ3:Z `wo!%L_V~׍Id6eV!r:Yx-h9e3SG ]i>Hٮs$ XZb¦w%&^`tU"|Uѻ]h3dY>zJzj1fht!ӳ70;B\9kDGҷ~qc" # |g!,\hh֛vH_tبL=E"ZԖʲy S37MƼ:ꠁzEhq IeQUM73ev]|?? `uDi}ZhY'/޿>lR[8T4e-kA1b/8c59\bP@ਔ_9 ;bO9DZw%},Kzr+]=8$!y59۵S+2/yh'W~C*Yx؎k$@e1i!""5,6T!=z#hF}Hds46N}JҫkG  l+NQ%NVEPZCc4ZpoJbmx,7΃4Mנ_~}[~ؕA94]b/)*ud?_D[ Yj$J/[3{׋Dʹ %(9 KiLuCw.ekhļfQ 8:F}E)o>\` B4elΠ"Ӈ1hMeּ<[3#P@7ozCVwiDWy}C )Z*%ݐO"¤T/tUDjCCM}*eSkNDSn0xrȘ*"Tqks>c(d$H7Nx%lۙc>dg]׾P7>ڇfUx+/U=9ox:[IXE|`5%j8&bq_7N ^__-ndx?D8b3>Yo +͕`;0ӻ@iq}; sJZe$z E+@fP^,nR68HBO} Uid$틐'9zpS U 'Z)^)J9p W'LMFԒI%P8&V6_!ywSoVPyKÁL!崲C~#kO4gB6't]5fuQ"2t[zb͔e9P;x#r٘CfF xE*58^ѺȪ_~,`UiNL4'IENDB`dtkcore-5.7.12/docs/src/ddesktopentry_example1.png000066400000000000000000007601311476226660600222100ustar00rootroot00000000000000PNG  IHDRӲg pHYs+ IDATx{eU'>eI,K$mF 0LL%$S̤*RTȤ0ńCAb 5SL0~l!!e%޳W{[ujr,}9콞o_|:"!&fbr/oϋ^Flypxz7fgFOv_>/?y aPa.7_s_g~m Ev|=|K<@Py|zZ#&9 IV'DnwZׁZFaq9$F"Oʂ*TR}ũwZԇnGϨT^ )/Y_GL|cs#^>$,DDuz?~ŗ;y>"LD"Rʒ"d)28l306<_zsuadֽT y ?m_۫UKuoX~\woe "Wy`fè~gZvKYD$&|l"Ĭ?SH[sp•SBxFE<fRntM7":Yj䤄|^}hثCuctհa#}rǾ>wᶃCD#8X׺2(%@U/?{ygyj=?NMj,T3+6 8[k^q5tF:yoM`&{2wuF(TAbdFv!$t?S9}ԟ}4t,'%*$N)s"J%&7L)Ꙓ2IrtIՕM= ܹ s2Qx`b⎤g{[rw=I",0zE5 _gdt$mr8IvaG$ZJP>~ISu:b)1CN}e;D2WrTl&H&lT}DM* >R[T$}L!C RaEf5nMb#NBU'Ѹ]jQ:&ȥZ#< А8m \~CSzsZ*Ci '6hB Puvҫ'9tE4+ )fP`:›d[߷9N;$Fg~pMw^gz~aA=R͞!b$Q\%?OLK8ﵼtP=ih)2`i G!R ?+ژDHڶ8ar(-+'_i5_ou3sRGiJڤ90Ѐ'*.5 0U(o7'^tz$S/ѽU?J !w9͸_3%V< B$ ~4br~UaBGѮu_w}H^csfU]-p' :L#SAШnGkL2uҾ'd Re+UTe4…DE ApLE.I0Fӓٟ<┲tQ-bGoczl'l838PO >,O-Em+YOԢ̍ۓ_QwR]/'YzNsb&ű+s)R5E VcS+ʬ_Ǥ6F0Q`awS^ѱ  9cN \G;Froz t))0v˻} ('=M+Duz.Na$a{:sB/fI8'm"c&Bnm9e"DDܸwe Bt`B;B$F'(m+#[]R+`޺ɦ1*_1IrgM*cͳw6˾&eZb eMDOI'ަ i32vlZvɸՂ}v=M6 Smie@smW$8}B丿FPbi3640ThSVePcCf$i:y6sA~p@#%7,% W7 q*5'bTY0DRnMR'] }JX+u>:KQʓ 2sqh-t TtYKm 5ǴZhQ YpO9DfkhI^OhSOt>ۉTKWp戊CƦu\` I_IL6qfԳ#F>iz +cm udQO$cL{r0z]q9L`ZHRA"4zHoik2kRhzykJ \m{%{:V9DZޡ9(%B=Cu-w QX.~PԻ4nj Zxʓ aO^S7O,vx&D`|D]h3DMU &ܣS]Lȴk|(֛=!PEc֯am$mZmH =V6%MVs4DmIk/y5#Z< nXͷZ㬁>alTkq{7?"IƷĵPװ}j3m5Nt/x_?z}0 wH5w;R4K.abB%dj!tCKKT*N,f5(+CQpЍ㾞 9+'Qb^p}hȲ˚VKZ0;X0)o6EQo>!od(T]ްZBP"H6BՆúֺq&") PpEӆӶ/)lgfR#p0Js|6T@ AJ4РM<9q98io<,oVdfj>3Q-&:WIC9@#DN`;R7ͮ7 ZCiQ\D2AzTD&Bm <',DE5HY&Mf=+o9nLAy\j-&//8lMt =x]2PhƦrF+xGiL &;9T@S, ux;[䃇EbvC!$.7)= N I cc{w[#EFcJ['W#Zh3R7h)$6E:Pm4^Ԟ UJߐS;Uvk؉ #-OG+ۖIrq/*'X`4ni&/s Uۜ0 S^S7)dS 58[uh_0"7äM8H 4\#20SbI݊Rt]1/fT O9+NF{.g(1\d;Pu\S$5ȯn\4J3 F+fn ɦ{ύ@93 w̳>HY'^h/jIcZ.9KXE"HJUef̓ vex8#@0xӧrUpr+ԈTZTx8PHʹQlBUhj\΢HkS twpq FV/rc|ȹjjč뇛JDC7>,%ZQ3ZK"]Lz #T$XzqOnVS<b0,m`Cu g;tSq0:ޝfe*>}2 #ָ=:x$yKaKU*xM`07|FME.o*p?-KX R4Bre~,N3Z1A eMM"l;l74\vM1PFLH楢(#XBWĒT=N`PGW'+#'۱&%9yX??a"nOVȞSu1!խ4_)Uerf;^Y8=E(q-ٲr-$V3($b+čvrgB8AD0 $\Γ S&!\-y* y\"̜Uq_e/2њita`& =ۛ~=cQƛM;ʹj{!f+|ԁdbsXgG.G5͊LJ}W,vkl$J #;2VDU6XL@j#9L '0wOR QU;%P-V3 8kVyn33ƌ!9?^& l\lN[zl A"Zܗbjׇ֧"!:|̚okI`WD9~%T<3|c7j8sڥ-EdȥJKQҶ'&htR˺Dl|w_L6bAbPdv:4rWҘјj=v1<*ɣpS/`rdCg:ā+ðb}@:X5R'O B 8P^xMi{65 q{KHJI,]F.[d4qTtSF!wdwOp{MՁ`LlKIzf4Zg4Qj+Rݮkq+LdOh6( SO4뒐DҖmeyGG4 4a!"du<TV>'(謍r#G( &>Si R^=cV#/bLQYr*'OL2|3 >Vf'@&oQJ7vxPcc[*.-y5Z.·Tk} 3U;ڬ> qDfNXQX3W`+"S"Qbxet34` 4h z&f.;V\i{;!35/$]4hĜq*}v=s"Ih&ۻ='2dQ+RR7bp@O{ux%mLPLgÐDbTtUM7d?4Wx| f`ͦUdjү$U2`!qzfD 8 Xf0֫\L{Z[ IDATQ ~trⶂΣ6:-0] AW+nf@\9ы=NdGz-7`n_c?gzvG~"ZXڨwy}ߣĭ|y/R6BN0–rD)4PqK^w?6|[Ҟ`Knxu@ NlUH ؃re!^z>sT:9$d R"X]:@ˢG:il:lkU-aa9ToFj|rEA2%A+kfVN\z촙sEJ]Zd!F/Ax0 kfL/"u@MM}zn6\%ٟE0%JKb/pU¢~*:ՑhBcc\ uh&k3iծZܢL.\sz+5ORŻC{ /m2VD[y~D&:TLjsL I'aŜ YV39G;kZaݖ^t«' RRF/_jS=Gr[cmJݪe4P]4E3:GR^U=~ N|6. bAbCjl t)Cǩ2l6Sc,gGWz ?y閧l3R)\Vb}ilDj){23r:w'}쵼\b?o?{̥͟;C>sOҲw~umGKmigng$=rW7mJF$h~C{G_9 '^~teg}R{0c)U uVg/i:9K2zYL8>)!D!Cگyb7_RI 2LtSQ}9I<Ͳ8J9S灦hV烬]΢Kƅn f JN5*$;{ H]i;f0kb%$TI+J)V㣉߬~[-wlVHa3u֬ 33/W4Ŭߚ]VcU2.@>V : N6&2Wm| ~Z\4L+ lb|_ ;iQE^k@0 ,qWTnr3Шu DIIh=bi9 HDġa:)R &[dOp :@Ot Gj5<o5KyMِ̱P!Hܭy#fàK+GIՅ=6Ôutǒ%X> yP}οǼ)ʀf3qWm,2 31|F X.a v CVuVf %QNodobk9&(R-S, P'^wZZ*^V߀BLr%\\Ll!I|AWD4Tu;pl3}8_I֢QDyXWjV_,k?}/^k;"zpg>=go,nztF>ܖ-\=~ ?wҗia!(=~+?z S_'xO"-Vuw*nIxMq;V3v+NQќAPC83Fi,jihB*C9v56敍HiH̡j,iPVF&̭R.xF%%ZmZt!ZQ@m7e}:0{ĩ?He%^Tw',թ vk;Dƺ5a;`ճRZ Ͳ\;Q16EʿTa0b;WQo'f&9y  u Mb/ +A V%uD.ߕ%}x 䤹䷹Rk#yXBSrQ;K 'Z%`F`jmp0юm Hm! eq9jb t֓jb&gDO؈MWG fԐ./o=L ~_]~޹ӧ=ӗose|//x \-vؒ:5$=vӽsOogμy?w*Yv7}*y[/U;]'^iuOGQ"]ɕISAG(C9?T3Mʏ'pxN)oeUEOFAjn좷OޅtHa0$5&}B)]e{魃OHA(C.L$95,jT3-]xtwk,ⁱ=W7~W:Ynk[_X/x';B{j(k 3 9D$D<_#W 1]$ QRF7"]4 Ֆ^=jL8xX 7:5`>asMؽpHQfMje|ѷw9l7z|eP` I&PڡJ xQ!mF([} ^b6 w%8O5y@̉֙[[nr %q cvQC")I&f{F3U#4+pb꘩D0a=xP>X(㬏jy`9Pki)ա3 aKw&Fbq7ILmqGWM 7N r_EhT+tI-6^s.հ-D? QMF2(Xڧ%\8م21v^*1q^nfVfXg(*=KimԤcic-ᷥiH812L`=7d_ЉI0U s{EsGF$#xmqxL^&q?2vknn\SDD[,ٹS)w,xH"[atap1=rUWv){҉Pίl^ȯlaPtӅ7$JYN$Er"Jً]6WyW]˧x0Oke>yFܤe ˷l5?=!*:X㢅+]SGl|5&U`P*E#3Ҵ['aR^HfVQRA.5)&lM Xyv m640o\r~&Hw*?R;Z=tużG06nNVX-o!z]( 8lyZz>q7Fc'[SaY4pcm6Wt ' KnQ5ibw^􎰷v,|:eJl DD$غ3ԛf [FT,9QJf;?Կ[F{LϥY1x>?|7 ,7^݃{8֯l~s+egn࿾W=n w?_2o4?rBfG.7|vm7p'Pi9Koxh_C~]#h,M lK(R!WaFҐ:Wb=cݘ/ԓXY[Glj-7=ý+Mˇij0(~~yHLЛ]`R8[o@|-mMqBg|XI7(Az)]]#wH-\uW7`cU?vf]GMmqnio%>cl*%PaI)2yV=oW`Phҝd+\u Z;,w%,ʢ)ywԀz gE0Q`>E..6uIX8ucu!* 2|Ov+ȗq hbۙ;hĄZ6zdJ<`NT!Ur8#UjAv$꺮"@Vڀ&I{i)@ؠ:-;a-{[Zc,aلH2WZo!?DH U{ O^zٛG߳gӃ>TjWΧNVOq]|]w!b !:}e֏#w$">?gyTo\cm:J}rv?2asG7] $f7,qW$>MNuNp?pKD~tN^A?ybr 'UUcU0/+ (ȐmH0˶ ƇMMf*?=Hh`V|NH ^(Ap7fOLZ \=~]V PyM+o|VǺ)<YF5øM$ êb\  2hc<1󷃎E"8n#*XDqbO%s)aK'uTԑ,zZ$2!ʮ08S"Zy#HEL,tk*_""Wi*xk&gַT얓Fffnj5MR>l `lT= 3suؼ!6gf5A%;Dd%iۥ|tLÌ`㵢D:j0߼Dq(TPRSMNͻ* tUk@?ޅft8Ș5-+~[>ԯƠ):iғݠF|WJef~/]}X ^ 'buhKz3/>@kۘNv0Wl `W-Q]Д4؂l0@ X/h`:}hD!' {.b'P"c/jCFT! _@B^5J'DcɶO\hU!&\b~Rm8C)zV}𛔾 3ն]l8juybw,MgfWLsyĔLD< BTK vjg^']nv2KϔV|2-W./1 @T; Iߣ` u^p|d-&&Ho `J>ݱw1Yl d%[wYmo |51ro*WP0=#Od ӵFl5(.Lbzfm\)ڽ9d1kƪJ;bQ 9@fFCd5qT7ʸh6ꓞ`A /QL++|m`#UB2J0})Sݿz@d5mCDxS#3Me3Ϙ'yD Q\m`+_U2l[}ĄqFasm@7{d;8ӢJL|AU&,C#;[>A$[.g^}2Fʄu妩+63muqt[( Q~T\ћ.m*%L6"ƃ.cU!]$8@/jT#"D"_Ļ6EB? X#>RZSV- 'q0b1aZU=$MGR7K+&%13q_#VB.1EǜBկ>xY  KƮfedL#P dTbXcAДTǮe(iH>MMN`5!|bd#Pk&6%ɔ%%UJRL17UoVUx>lQՕ6#)F.ZBwB #Rvje-DbNe+1XF|4jꤰV !(>ڶ6x'%W a 3M#ha6x? IBX mq؜@-cB~C,X t.x!1/0!Da/u%ue >Կy4nݴ6hcqh0>f~~e68~MLSMLo!Bnm>!ǣlȸj dcT"0آ{X vc@~/4X vU>T g&:4ETPwY6(*lc^ڟKb5nF<{|KD`&EdS/OLë79 ^&|!#5D4؂!FQ:/Dye4KeS5@6Ʃ+*z@h޸<ŎZGL9uSx_{бZpљ)HF!-ֱ[~ՃXwp2 6Q, =;ih]ٍ *. #RO| i.?Ǿ)& Bd{%xx#BK 7FSYL0`J rr2VER2'3cg]+C2yj'VfW3uq,x"@pęV]5u(@8;R%~7?q#\昌wE8}@AA%`h^nEPՂ UO'xY(;(C[# TS"@1RkJwm`.5 'ZwOm.v:AD3%a46D,V'Dr<ȅɞe%] YDY ¹dh\$DY-8d)بiZ *.Kq onnzU{)F067|.*h.Nzd Lb|Dc^$3 rq- Gˁ9[UJ}']`X2K,͎]Lks$ӏ Q@i |M|uI5bʣ.^:lW!u| #CH#0gW ȲFm\;f]+yMOf I8I?mAG*jM0&dVV6%>($MNHo$&D`to M648$><_h`}*FuG+E^K$W 0Ob(.Z1bXrq@HfGpcknJc=['op\h5{S KeoǬ[:%azQ9 Ri0YMm@_Hv3.T@wuAL.hB0^s\,:01ٲ t^fd : G2#kIjTh{<}`b ̳y24d8botXR_Q~1jk{+ YRݎtLYdX^__=Ȕ-:xal.f\6-癌AMWDA\HnbpK56}s=$IǬf5+k%tH$l^`U,`%3аPWKqy> -E_хr5X^ׂpZ ,,bj( j}݅Ewy[tLvvt59ejr;l󅋲E2J Eྚvegդ3EÀXM*1D<)򦠡>BIfMA~5fs2I*DQ߻0n }ՙɧ__}bq3T1u[}^ Sqf:ȫt/ougTGx=dNIuI Qi4c!1Ӳo+t sLC@Oy=offQep☠P"dJQ1$T5O"fHsW[֐BlD "W\MLz'Vl̬ڑG{Bps_ $GIFh3ua%Mצb@,J xGO`h˴O}A|!PLWjБ QLjewњ+V9M?b߇ XuhtSYZFćSf ggjQcS: ӏ 5K5oKӺ2*b`LBK&pB7\H! :C0>yy%ke);䲨y??7@}DoSYmZ"`*9(u6ڰn z+u#a}3{UL"KX.]"Y=/0 חz+Iv^frjg]zi S( 0Q&tS9sJFHDb[9dqPg!~Ot#Z(g/c*lw$U@V 1~B3mu}9:_8Z롨m bfId2$}د2OtK̇$|.nwgSr2R_P"3nu|Wgp'oy=գ|O/l?stllIL|zOo?M}[/|Ѻ]o?or(cȘzɛ\+ b@!h[2)+D6Ⲯ?tkKJ0.VMu6Kj lOzn<P^?%g6 Lyat"c.Y"mHx*O 5L惦EW%=svo'T2]+VffOix-/ <>89 ]$h)8%g8eԲ['̜EOӕHKM],ENrU] ?j rPݼĐ2Q`EaOv8׎WG+\ܹIY)N*BC]stQ@V뫫UJ uzZsbDBȦ;]гP [DqOD`B$AأazKROk`3/x;[Q|&$hӸ(ֽ`JyG rz™{>]o5MVھ~z}7>ncZ@PEͭ^K[Un,+?tU =w᳧/.,e Ww 7[?o>8?]+Rh ƆUI(uQDz%@9!1P!=Qy&M_$NMkY!W7{ԬFG.MVq ĭ)h|1scwB5uqT.ѐNEr$9 ZtSA2oLkwfD$ɗJ7Xnˤ&}٬FDKմK?Ng(γ#lSBju΋D`IWSm©c¶ňJ>nXSf,V:SIHfd) 2$l6ˡbL|<ݞ߰H@张RɈGYODyU$L@kiXM `zWf}kz:A!Ҁژd+ћQ-;H0(Dє^5:DrSdjImR#9 NO{R@n/9I|쨢Z4TNgB"!xyC?L$o/;n/ro}uW&W쏿㣑,sHQ/<Ȫ_Vt$sb; YV}l0!zjW DB7w2a, @wµsN0N EC:Vl$xfFqln~xҼ^ζOkP`}tk]EAw| :Mf!>),[An1í-<5^Z b#G}2r|,0j 69 mR8Mu:'հ"qRD7#&-5FJݝ(iPE/Z"&9EΘ{*h$&F %j`FVXkPvәSGw_gvBޗ[,/^>X->򅻎VU#_MW=놔wtg?>(^̏~ߣx7?x/Ho?=_9_ēϝ/~?=D+yUyB F)OO^_;G~_*ˑ1P1,V7DaCX 4%.jn9PL}ہQ0>)-i1÷n{q}o8\_ʥH^slL2 nۚ˺ DgTբ0,nDBtp-v iYQW7|3008D!'DD]ϸSwW]=E]5,AHaC&ܹ9|c>(w>>]]I~ӑ EFn+@h 2򖠴+ f*$ߗц\f9/ \!Oy}rB02Q nYAhJpyLM ZrPD05fDhoH  `Ht&4-r\TM6x(r g)W'jryZkaZ)XE #o@]=PQDUZ&>FCf(S>(G +I#̠(!V/*ώgFx'!j=HkNag:M,ۘr 4|r~$(f[{1e6E嚹8|U'z&Dw)qFUf^O 2)=ꇨuȡJ)=(~7pqheZG˫"< ]_~/_~]qDeĸLT5:%twsѡ4^h+U8qۖ+ w,~gיԪguNzmʓ9nG[uǫ>TzW쌃Wq*M\|72C\Rp "X4{.3o{jߛ`si }#m Oxh?9i|]ꍧepx:?8<::YF'KCer 8guRQZp"{<,ECa}7*8, IDAT c )q\! en>b%\HY4&ߌ.2p[^7= "|*MabGd6k`ZV |aFc&#*s-)(A!6LlpsxO@▉I,V0؈H`- 6,Z%spw]WD)"2{P9vJ%HAT_:_ C98" #uN yi1PzڒW~?][N}bA xt/cuzf>U}_K'$ X)S;m=y9^^>WL@cY>>8V\pu W{+=*cmxd O #&Ĥ7By dF88Hwq u L& !i_IsXOnD*D-PͽW xPҜİPThw̰oEHMhaS43gviM~HD3^rڠmCUKĴkFp ,cvVL Ki.*G eC0i,oAG)Xl3>'̋\1L㥈Jٵ"2!=ԫ^`@lzp"UP zN&{ Dl9cJ\K8:Q7cd"ԄN4J@UW!d[hD)XQ}13~<E5EQ" ᶤ#AiP^L}=Ŝ={}_8VǂQko{j~Es-]p/~]r͛On4]7}}]|qb}} 5/_:fgo6~.=n᱃o[*E0H8sx7/l\s1D;??w~pJAbT -^OX YV .=vũ:^-!(WnY <Ev)R?#=UշaKvT?URҍ^wziw"u}`6lG4n|ߛvC|s[wkj _y{^Ee0w2"IRU[vJjWd˔HWFrC ːCB^ݎHKӋDt )8W.@9h/R͵wwC® Tuʗ|9ukm"X;6{>a&Qu67&ې>Vheyn?M|Zy? C2g@A#`3:!7OuVB~_ 92q&'r=(]46~1-LMKm ,x֟P[ 0ڄuhd?0` T[DhmޘraڰM)*ꖕ zm`>VHY\1@T#փc#4:;˜Ox TD)m @-p,&).%4,+A@Xݿ\;NZ^ 5%R qR.:ѝERN;dQ؛, EXVv'f*pc"~SwXR}QHNiBS;%tE28 R+"NIe o "K?+B uÇj  8srҕ7>v?Z23Gl̓w34?,zcs?u[@;aDypdfCGٽ5wc[vy݀Y3=mtObWo~}/>f壯r=l=Sc6Ń;Rcž=cqKƯEB͎2:/|ѶRmZ(A]%To85 x/:z}v)[:z; `>^~SHO˓B@yPJ5S@ܟ`!#^ O3QD/,ŨߦЦڔF7Ih! e66>4!QsF|:f"ֻ$LR VѲGhDE} ۬[ݝ K^>.M塽Iu7Po4="DβDb=#tm.'YьȋrrntDDD"`-Xr1v]`/+ j#!h}ҍqaT{>OB Z7.튖yb U-l4ǫh];4D! D %JL# NIs\o@~v{.GH;>9Q&ʽeSD4jtX j‡/P@S! LQ4Bu&톶 l[!|uIM@€d.{c )31!28%swtB0n#rBiID /ƕ J8A;]Z jFDbXVTB=Q~<ޙoI? 0+(?s\L)YbcVx+lla`G!ogvoP"2"ÇxWλםųl4O?W>ڮ]#ݣߤ+o+ok[TcYX {{;#{QWG&Dj6Mwd}ȋ]}m_X͋GnVǕ-\;ū?{#>{+glnbYCrJ"pÄfS;@d*o k{ 9 H sQmU7]W׽ .K]:gO V,s>1r wo꧲* I7Q4#.苬jnC"ۘvTw$W+"K.YZV<%J&clHZ+/ȩ~a WbPv>NqL0\ؔ"`d/>ޥd "+S ]PX&X7PwCM.W|,M=?gGA yQ_n7j cw+IPMdW&^QB"@(KűJ$ J"f}p1Y-HRhqF> -hV/`r ?Ѫ%dCt=6 A44`R+'XV` M*7#%u^s@_0.;z$JF7K|TW?A\& "u`xwF[2RYt VBU%IV2w` q>&. 2i?v%gQ"({W^-Q;d[&z/M}Xonz7.gio"u~?rOp@gB'i bt;v!B.'{V$එorҏ&_p. #|Ο];G'xz# Bº9l}|{A#;=~=֯m+xϢ[/En)fuz?+7h|gZiš]6>J!#?3G qR=c6e% ;[G#ƲW!&KqA2LzCAT3f+.RmH5ƨk C*vY=.Uxa6EfcSG:r{xQ)q6FeВcLK7YRhBMVh+ H nu>1e^D]} yQ./ 6^uVtJpD wQiiQg`JFwC!cdUd}?-Q,k(?E^F%FXDmZrP@$5VVn&IMr J $3;aQ*Gj#ΖyDĜe\hZhgϑC]#ărP9@$M䁑٨ʸh1N$=I+:~Ri EJŰ#%N͘NJ1"D*??ٲǵ.=be,I.H> L`X?⍄N]af uLNp!%̾EK#Ix_ox(U "ӋIF6o-ڹGa{36 vX }m?w>}\e[گح?/ZD",8 O VکV u(Zv_ow1.6\aҽּ ãMDi;cN>oz2$.~ˡK=#-7$~;m0ص}M +mOp[:UieTWPw#懜hsH`֞=Ϯ[ƫ 䞕{Ѣ?퉴gŮ:e_2V}#VLeWUnz$)Mc4aJ cT݋aGBd kquO0񎝈0@e KFp8 fB0Z*@(ݖ9ĥm@Jlo65>`.Hr ]۝͠P| 7B4Q1 J| -zra߂͟F&pãK|ރ#-w<0{9r֚w0gus'%mh-5p7iZmo-'o1+᎐Jq`{y ۻG|zOXq{3kp'v]O/mv'xtn2L=y/1t[x {Ț[/1xn)W\{i{֛拿;sڝA? Ow[ߞh(kk^v3of _CVK#ҵ5{}WǛџ"u[zYWK͌oNTӗt\=EQKh=^t;em:jV4]Op628}Iy Y@jkj:'A[-wXk*5GML`jhYʪ~(ŃBtO33) F^BB:h4-7V#WB~QFNZ63e]G%ݲv6' Id͹w'F8MA<ٽGEeqF!Jb6Τ`#T4e4MOrH[mtf[@IݘdRxضq;n_bd2VgQG1܈kӞQ?Ai/aڸҾ<TE;."= AȮ3[L?HOecV$A WS8M۔ѦȻbMLB {bI".ե|8HxZ4>D-JSc1=mQr:OxPz/zuϓe-W쪓!ix& sOZ-]?_#-#/5:3geՆY-̉j7;gO-hzc>̓?n߽|~fEs4|6ak<&=b>zYy?vحO/#Y$] ;A{}P#uK3;ZJ "1 Oa!tD82A5&MW>XEY䡐#qbuh͢;Z 3lDO_\ʩ\dט[<@8/Pݾ UX֥ J(kk*'%ȕp9Iؕ0JEp-(XR#5y*ڡ, ǪQmC{MB#ڑ#&PɿiLy(AzpZ"{d֨7+|AR<0r#ԈZ: . DZY=dGxʴ_T莛 T.iCz(@y4Q)[G?ѓϝ6u㚻KN/}?=96.O_[NZ ?-ՏGOXrݼoOU!AGK_}_CV8F}K^]ꆙ́=nh}G~{dpʚ=zϬrzIָn8 H,hljQH,aQB)4RB($mZ%8:Er>Y@*^:,G!O-Y=5-,GU)3,a%*b,KscS"(y#oQ!IFIOnNՁKS"~ڤ6.x9+KYDoMT?zЉ>l[}ee[kIjRŭtU~pѿˡYu`=:Y mlRS XMoewol}]> G^4M3ts{۠ cn4R#K[z/oՐ8nÀ*F- ڬi$ܕ'iE*B|".bgIOJcB`S\M jaA>㮱 $a1wNFڻ:;'װ4dB@`8S- ˷w:It `q~:qY@2W=@L0Ƣ'*Hu/&@R´A,6%wru)fP=ӻZKD^t1Xhol/`k`o5R‹ _D [IP's|~lI:T rȏVG },%pf8' lG;Dَ "`CĞ b&]Bқvh>-¸D=^Vą&_b-It]#XZmVRZ\M<ݔi(bBDk?# z'䭓ܖKYn]:>UUV2U0hʈ'Ntf4pfF1q.q6+s\?ZW !jHb>eXdY$;#:ͣ*BgRh*딺.$bNq?Z"[S=HpX ` JQHH($&KAxq#7J=bv8 THY\>rEQT !'֢\B@?IΛkQc-&"XbVDG0z\Ay5!#h@A mfUHhZ!]'ᷪtz+ŽDc%#K\ňxH`c/݋b-H+<ϡ+qY-)6S\(vjgNCc-C "BFdB`G M2`7oo4lSie+Z$uDaS h4Ĭ^4 ѽ&y__$Pbqؒ,qϐ@6ˬd p&U< wTd)5U!t䡄dhh^#`̇n" I ^F" r<8h{ܰdwbr/jTZR3ad;1^,w^U6MVH<ꅾևwdd&$!)NpS%m#)7֑r[6bOh2K]RqMv%E;a ҈ aMR҇F */ުxXZ81Bi@<> 7m9C7)ͻ$z{F{jxy7Y(*;@ͦik+%;p8KѨ|#PPG( 7 r&h: ICJA֑-#Y$ҡ%$l> 1PB[p`-  EM̠W~#DD F,">lH-SX/R=R-V6fJT탶Yb7 J-OtQ+ JrI* IN QE"Q`4Hq_ŒJ.2Ay=pE 0'7kE\ 78;iBQ, 2ih*Bu!K1"#.[j"u\wKCєYLuT5 4`\r"EEvfV7aV(0ɺ;/UOV/4.` ^U9vXJ܉taFz@-7ȕG̙r;auaLN;nL>$9+dꫨ$|BsR72%L [K>:YLъXy>U^3^~By5I@} u3H!kHV~MS5*A85YÕM.98RzLXOiS4}#SZPyK(F,;^Ii]7DP~reh+nߪMTX-Ϻ J?Ѹ;19u4Ơ1 `S䩻=n ps2~709}%u_!w9.? mxC~r$:pD&5 R D.fpmb D'x~W%CǰVBҞ_f5ZP+ʳG&5Ccàn ,bT%VIYmNi+b] Ne@@k'&  ($+f`Jƍ$b2: ҌJKLEk($aXɘ3nq/h, tᙘ9jjv"a ,)UV*$o=B;ZYPi Bhm*"ake1o3' ̘$'^]qm$J,iCqHAKw&hHܚ _Ll&{u"RU' [Tg*Q}L<$ )&T0j'x1!'.1xނɾh2ɿg9^d$Z%Suox(S( i @ /qLP25^\~FٯCKd3) Yk:{ۺ6^P#شPCg 'kvccHݽHL\j8# aD;1޹6i4mƠ ' }Fӧ4DZԥw48mUp876nc9qCD \Ї<"j-YO/D'#f[̲K/ #NZfAQa2v_2ť?C@\-Cg§qH${-_]GohZRh^@c T %7a*JWpa`t^l@&eUSesnI bJ~r?EmscGcT:aQRI%#&:i=gW,D}bY?r\j畊&/qSS`v <x-9ĔO<(R0|)O"Y~1K3>O'wG q 1lGset:ZA .YLt[" YO+NZ BFgcH缭=[MqFg|ldep@s{v g| G'˚M4_?Z 3d@M"(ij,=mmFĵWR5Wm[1N\ЉG" 9Ч[MtKpr(K` I.D(L]+ c /l<×wB kM9Z̘{ A:uޙE  t ?YK0E&Ξ9[hk3` 1&Ƹl҆\ P4P֙gA0_"ךaTJ|_Jg:T8]D| F^>;}-Z( [sЙ0؄#ѱA k CuE" A[D|3_s\A<0,_s MUѓ6ebxÔKPR#$:yHeD d[YĒ=Y"ɮOƤ F;ELU-lɚo0GED(";I+~8どw6{ RA?5 >L{!mcZ܀Gr7)*KxEM4ƉYUR.ypZ'|d` G_q1+>s>m 8Sb-H;M1+ ъD5{(!B'GDxRp9:t̾kyd,(W||$$Τ)؍MT毸h>bF2* d 9i3zy )6Od rZdl7|/^z]…l6k. Dl0ha;j9ȱ< Xk e̡Q!MG~p E#K&L᱓ aؕpnC`cCL]61CmqV@ّ‰m=h"!硈 X @)%u/#( T6i|=o,GE Lezg 84S dufws#"E^uDKhs0}m$+b=%nTulRF7i) +m0jC6ո\41 XQqF&2NXSJsBPV궶ںVM_ߍSJ"&!RU܅ॳk`!)C\pߕԊ.A4;8bʲ*ù0eVD4QRz߅g/;~E߽dH{5>j*R KERxUI=j/~㎧ )' qV)˻U}v޺vt~ME*gw7olRqWM{-O'*)^[ƴ84@7>qEeRRï:=} !񠑿{ SNm IDATo,pEo^ D¥>sqO]x%}#!Ǻr@T4^GCt/)j.ǝ![1 2j؜&|3b;wtQ.)CҔ'[j#*-4ؑf LܶvUWҦwFI<!-~*"M&xȧd|]@݉ήdd#9-DY?DQLQH@ [Y a$Q5X7!*U`K%Ba-,N"~iOK_][Ze! DmOI;>AWG3&./u=og~y5WܾjD"5~~~kqhe;#W  C0Xd\lnEx Hu\Kiov9S/\[ߓA}o=З姵xO#ǀ3~se-14kcV1@}O޹>\ljN,{I_{)>_?-g4/^'.3a{/<hP[/8_~ka{Voq``b 9j#qF\6,4+`CKvj3;#uߑ+MA*!DD gn=%iJP$ЮU-Z/D]y2-~q~0P.4~zMP>.^1?pΛ7|<_x<|B`,xreƬ@1]a5xxGH>O@l/@{ @ڰMlCmSp/5f-ݦ"|EcM yRXqCj$%^ Fz1 -G7LK݆n1b`s{%Hty&D?wPh3` nJ&J.OY04lh<|\n1_9@YgQ#FAjrǡ)mUҨG{07ikЮO{ZoS(k#!b F='/z{Bԥ=uH0AK!0-T/uHhV!D/bQ(`55^'CK^Dy|44'>l+ P4n;^ҨؿV1d7 |'`#IXJs%U8rl,|1'.%x"Ƚ @Cc-cx4V)S<控guܢ,듰A;!ۣd[K]cLF`r@ y/}~wF[rI7 Lmbrs|aޡ u=YolSneǭ誅+͛l `yooq梹};o~;['M2ؾtkM@ prV|7t­sxiZ/<}W|<\WNz;o~~н7>qwf!UcdCduuO;g袥7~g" nHBִ'i?JlnZZ]776Y+"cr OZDZ]J?U*I, Vcdih̰Tj":uM6y8۬whwAXp9WǺВCKƦmU@˒7iBrqk/o,hrTpUHϵulZ1U!eqmȩ&Xvȷ?fJ̎qAҀ2arV1&T0@kA9{+Y%7R"5D"#(9iGkuOXmT總~7n<-3+߹Os{?s:Z+?3Jw.;m-^#mQظا/8y=#nx9Z˵?M/xZ5w34[hn]wzkۦ.Wv^U,=СͦѲRGw9Ɩ;FO[>o:yo|OˣV5rilvv}k V,bC_uz< zk}nx{|p\pwy+?pNT 9xûNkpmV~ƿf r&B1᠗/^{w}^Lc؎Ccmk|wG^3`5z媓-72QyJ y/;n.,6vɫLDVr=oqngK͉e-"(G?;gd` -C*|kޜ댁vZ f h}GKջ'}^s~xm gl/W_|QWqB[+n:v}++o|]\3G-ZKn/{y@0822Q5rÓ-ct^IqaRvxƜr,@˛'s?qל( TڛcS+璖 6nkWyz-i,eCxIiL)2|ڃhĻ~4CPAG<9⢂[ЮQ mY?!*h7Cf9YYk-S$=Qs= @#+Bi(9TAtp;y6)C.%>ui2F RʇWk-ؙ7M? S97ܤ`pI=]h@i@()sauK R QHb>( c7AĘtd>H@*E4a 2 Cb;YA$b^9(LU%f5\p&Ip%:XG'?i5CoY)Bp5S[M# %os7z#5Tmn[w/cќe 9Ϝȏ^{ o|RaZS{{z=Z]f w@4Ab^8?=o`ga_8{Gmb }O{߸锕k-mWοz8Mps_9{?pJMs߳}K<}3)grW[o6u+N=j rPLuŚE,No~C6B^"Aw[enorxAk5w{ޑ/tM:ؾqsnvÛgn]u2RBԅKo|W7v>ya/N֊%@h-hd5$Es|}??-}=v.߼Fp?s/Z2co 9÷Rg?۬?U\ؒ۞&D` }=or3kpWν;uzQ~wg~͟6ڍԛ9AiV]9 ҕ',mɕ|G>{ݙol^4{'W|_~0^-d]\.6}]5;/jD۳N?hղ;7A{YΫ?\kZ\a^X'sNL`G̘].V-B)e0[za$h9B=1(j$e CXhrP`H춭NaoLw4$`t`S2^}ALmLUH m įlx@~PF%Y*mARF d-XAqm׊Q_u-{B=o敇GX#qx/rggz dH2> EӤ V(>bMzpz#o~%łI [[AMTARPma,ni^M§]Qx:h0ԋ_(LgE;kԣ*}@|(AQx_u>0ܿQMDad|ih;{K.ϡ~/Œ=ʂ_Y~uDokoGU卟Sl' }2⨯:~FgQGpgMY $}{?=[Ux߯N=Ur=-MKu᣷Tln߼Vml1Q:cY_fDhBW+4LW-o{!L0tQ>fu_r˷.>o}kߜGwv>{񌉃wNoLxZOvU:~KNzey5ƎKN~W~},oǎڭ2{rٞ;[=.q+,Qdweo|nǁlbje/ԍyjk{c'~Mn&U<pO}!k- Q1J{[#~hT;q6?c,!Ui`JH#jW:]F9O4+^U<;s% ; p?9n#(N ($*0Zc[72@aL [E/r4`$J OOPoMO (a4O8-@,uDLTTn3.#Pm QwQ*}d&Ҝ{$]f yaKD9K2Zo <%O>J22HNjl6ݍWg/"ld kr 򭐓H뤈4  a 416hR[u֤}|[$H23o|k?yk_×,00I=/m`p3lH^om+fJƝUٵVOacO8߾ooFt4L̜)%|^v|¿7)?y]]RHo|08lަ+>O[cr#Wn"`llNf+<{7k V<>Mm'‘Wb";7}c Ox=[,ĦT)a:HU[ =DlΞӟ|4ds V.8RjLn- Ŷڊq25<||f H;Z{Ba4Z~( 3;7ϯޣ:VlښGWui&,z`L)2q:uzg!ٗ;{'$ 6mg"gSMv@Ms@My @DQV3W0i*l5q҈DP6/rͥQD YI*O^Z`jGPB3/ b}[|[+Ci``R1 1 3F"eD}Wotݧ:lu3KŤNi|؀%$n[ h%e#®V'0w{75Z+8a1N<Ԋ94[Wow%0wjO`ԝ$ߢɝ2 4u'z鯮K®횸rsg o߃!%ĩ;F.=KOzI9d7l oiI;߿|ӴȽ6v 7>Wt7-*ܼd_ޗzbcXx;?-`ћ{ ;&kqdlWFHDqnD@{?MJ=aՖ)m)=[L=p__/rknYrjR+$ nR[J䧯T[^<=75oOZ71õ F_*gF{w5iɭRaTk)QR UX:RMq ~{>h|bq""npЫDFô!t%xB{Z'K''" }u鹅9.Jzq`neuz6}2"DI 12j=:2v\.d~ UcT3J5UBgk8FA$4 %^CC#qMwשm rz)\&TWovi}sT'6D>.)A?AӨr "LE,qy8gƂ קMfJB#)9I5? 6Ěo64Xrz`Vّߦ#QmP <:Ll5}i=|wTp듇~M}qz=g֎)Cw>}p-ivgkgJ\nt6J=CܹWғ^ͣG/ q[ϭ;\{&h/?;;^Z==^~ڋ}am}!CnW{qw_~Kꆘ#}}Gwߋ[隻>&ڦ+Eef,W`Ԟ]~߾ +6OIm7:ؑ w=wЂ=7 vvļMwX:6;}:b \qDv[X)iXT?.f# E0ֈ(Xx~Hxv#M3Lhkz/>v8,9_lZLI|M&vHx؞&hgw?ZxW(ۙZi{_ۙx9MRcΎ-tNyaKwKkv[0w˧N}V.&`KN|?^|r}ʌ`Rl*OYe?4Zݡ% #õ^ùÕJ)= QSQ)KFs6Z/* l\iO|x~\yҞQ^]ʟScҒL:o] }=K nk~zk}A +5 RY`.\@eGZES0U{]w) mdBY,}FPʓ(gw bav~⠀ Y 㓜Mކ!BעEi("3l 7|bR3'آ:iq}Gh負<MSdI )9(O5bKRD2tEU DqsF`ݣMq4gRQ4dHf'DPIpDزyzά H`@  ;PY$f 5`,O-)W#V0s<4P6S;r0R#0>1d\ALY")g7MIU\(Lx^2fP,%y5bfwvs6ӟ {Z9-|/tW_oͽ4ڋ=o3v\oLLtK输f^Rs7G^sۗcGyg̘8to3Ǿ7{'~~."M|KwAۀ)( i}v&1 S_r{@S :*mw6h${ %e%G Nwy;,fQwid}1T*C!Tn[pSJ 1sN! <\ .7:@4d0yI~jDG10cuCD8e%Hdyߺ=cKCPl#5@҇'#3wE*̜EU]ݾ\B̦dǠZ&)!D R1 ijVF7ǰ[G0P}1.NF v¶A1pᅄȿW D1ݸ|, Sc[1vsrStJWm~DE \t R4r7 Ч$6r&_t  + [;D: )m }n S!2)3 Toko;% E[R K/?텙o{j# :F>k +;T;?~+ÿz]{%~꺏ox].EwNB3;|gkf/]3kV#Xc{NdoŸltՍgmv_FW ?Ed ܁_zRDAQTZש+іW 4ReR1c)ވVZ3҆/0o?e_>pN$vKpp!qcԞ?}q{kμqє!!x}QƇme@ ]fCW\Z솈n#L9\ڀX c^ epμ*ܿ %uA[ НQSb&;)> 4Du!%ң|z$в,Y/>>O5z#k9hʌbB < &dJ1U:E%Pzz!jt\ sK z[IGr!~/B=8%),(BԪO]sF^Cet+Qm ƴ+"X>imPxUY_gwfBN;CZB<%J)S/[gJo2u喩rWo11 5]6N/1Z+8[,Q.$[z;Z1v)[3XfƢK) lTR0qʂlo!Krd iZm/"g$y`eYp>k{A #< 6n i0DkEPkZKlIT)pxnQsl,u.@l!OO`z̬ؔ Fu1 6O~lӴfQidQ*Oi#:` >ZchF2밥AF YAd JL^ca!b: XHrH:Q>|c_DyJ@kmH NWjݖ\"\qlgK%7m!BCN:uN?y$d>bEخ !2"1T$[M\PD,i4Q;FA>)l'(&F'qE3vH $D15,ȶyZp+2EKbXBꨰt3 c|g[z}\E!bDd\O5|)d Ԇ(K*Blxͽw"n"R@S[R;[9!r;?|]Z`DI]9$>"y[9:jP-H59O#)K:Q694i%/"rgt &Tx۟;80%8eav[(-0EM\ ޡQk;%;7 ~T!H'.rc,Vod@Q$&i+GyFԚk޵r')gr/i2{"WH SD-(PVb(\s"!uPF!xgucZ>"d{x I\n#] u T3޷e +9eu ScA="_{e7F>`8$A b{e>RMfjzp4#,3 Fu GJQ:P{5E'B ,pIpST8mw}ǃ',Uw\ N{A0N:ef?k <Αc=&M҉=k`cMZռ(Dk(ARB@KrROW*'vҧ+q*VS |zkP2-Hyek?fL}1DtVyr5n!ݭ!}KL3BpTUA M[^ !P8B\ Y){9YYq ^(͝?/l%}AY2:B}SRJ!J=Gqegcl#.?Y.%S'w0jpTz{3̚ YGkINpm GgJr T:hх}9732`Q>n E\mrDdQjc @ÕmQ̔P1Ѐ5fdNI>@VU I6= O .PnI1 YIzީs=43e֏4F5!=&3E9[):AKz{iBa2S^ A9W2yvyRҶ=-49ћcu7!k^ƋC9Ӫzxͯ}(0j#]]x"Mm {JE)-K )0}DE(LYWƿnE&L) g(5hsCFq=};tƕLuH,f z'Y%uA@IR<;1\ė@ڬW/؛)ofp{̨AH!u/] AaO_=!O{Jt|3sx#2dKY)eD ) +!]ЀMx:aև+-ɔa0:bъژ-k#8lЖ@llds3ARTP`ԥ,!S*aDi\:-]@`/GΐF 6ة$sO"JʖVK"@tL4EV jz֣ 7nDAt !iW*1DZ_Tě|m'}8j557SDžP)wM c+Cz'\dqyE[+M1E#^X帽#4Щ!7+FYz""bApt ZID(\Rm-^@ H ׎3c8cjΜec`>R?5,)?=5`j%Kn9koGyBL+ ~N޲Nx*!L ;rύy?xۓT$A5_VccE^3%[IQUw|pby# @XOȟ]4o +)XTO׫זrDOY:fPҒ2Y~UHPʝ :H2:{[,!!ƐbcbEbl%,Ebdg#؏zlIz0b`Dض3T~oSFH:0nN≬"w.dx+0VmO=B݄GzTJ[(;7y~a[%mU_Qљ9fCiy9?ݰ* ~]Db;Z+!~IM;KV%Q_!wjd++k[:]/J"Rn9cFrPZS> SPf˱m+C fiA+fVS*qd iݿ /`yAAv5h3p1aiC-dڸȂQX͘zW|uWBp@bW/O  d!xgt=$ip/'VMlrD1ZaZ;:A"(^[OVٲ`@Cdٸ}]xxh XA ?X :S" F@toA5=HIw&ybۀVas Qq6Qo–Ke 1l4/@-[,C *KC#rrObA "C$SQUSni1 !qxdu :?( ʌǣ| FDG ń1؄TF#-vTC"%$.%26аZFp$SI~ Ry';2򗨳r|ހ˼J҂!95 v"2FX@̦Wam?O`Y2M G'^#PhaYS^HX&K*RUQ c'Pǂ[9IjQ\>c 1G)oX;R-8:ZV,=&n[7!GQSfkycc+ iG ,!VBf> < 3 u&s,͔VN`f!&DO)r_Eш; PNvkd2.ٖ$)̐~jT(+H<ӝ5"ktEdq1A{;v*}*B6`"CT(`9F#<ß!3mx  ڀIPEcpmID;Ŕt44nVL^3S:I*[P6N+l6H<{.dykß3UUw f9զb[`ЗFB<RA /*86ҏB W%͡.,L 2Jcܾx;$&r>@ -}*d mDKbr,aANMK2y÷ f&{G 4Hi_}VmՅEHP]lQGqony\ QTR4\\^1q`=}<:VTOS[qpP gllSe?灂뎥ڣL HwtrD8sgx1H;ϠpvX v nKMi-j*%&6":дY  cU9{lqLEq C SF#+@RBSFтpY4E=1)F!jӌ ^{[<M T[EkO-8%w(oLq LJmB ='TF%X=c`6'\$ =0 P @9)w]ʵ$JZ irulƩftJ׈$/!EcS*b!r(,$c]!u$'}r7+&y cBX#;zRJl"r/.+ok_xVuRYk) l7q)D"2hГraK4>Oid[dK%չL2CB- BZ3 d\^[ŊDrvnQئ䜌S??}dP {n©+Uc'i]j8b Ry^zTꗴ$uv^)>Z&/Epj<{:6ԦpO aə!<{l9JWyu-R!1\*ƒVwWJng("HLWmho7ך-x"A)`~? MC QTHXfK ǒE- <X6$[W 3c&MvDm" kh5&0DjPPpj茈vw1ds@^.@%0F%NҲ+b;JXm#ui'p{>{!h PrK1#Ng<ѓ9'FB56}6"V>@F4ASFƔˎ$*H;?WպeM">3 y6e:1v+Q(f .~RF SKl%J+W KOB M^HO\q"l3=O#GZA)xb\GF̣.\~~Ch/2=4&Ʃq)p{f u]*:gcˍpSSTQC^=' D0<휲`GznS6ww|痋IRDrT,TU~g_y,ݗIKV[POo}I[mi!=7{61 8"}jsA2-eg԰UI#LRo*auO;C(9 L)eQUdAu(!E7AsF|HQƌ}tCDm+Rjq֞|0RD >0a $;\k3.;Hq6tB3(o׬RDGXE5?Yʞ7dn0$Չ}4}kH( X5`FG[(l0P@!v8c%^7!V@SRբɂn>XraTC$A\ow$q1CY%4Dh"Qvl' Et/F͹S5-p2FiP-M۷<:HeoVr \ ?[aLy4OQJPXCU.|<%𢄩fs,l iﭐu,\bTRDŽ\ lBy} ͐V1H RNQ~Pc)ګuZ$S7s` dRg+n#o "F)}lYۮ?g\siD0}֯ZO.^i s| Ү4qaIPH[N\zcqg߿|[o+(y MylYI3bڄϝ ޚ:awsFnl-]Ӌ4>|+yc?l{_?_uwos/q[?_ Q㗫Oѽ']sɃ[cG=Ukkf_㋣`jU->\LD[{~x)݃@:In[oҟ'v=?$7oЭK"}(s2g˗~{꯫L;>HYLCEzxXv.aYeOd@AmĐy@0udF$eULjsX鸒 ,H\u)3[+B6 !T]V&$ holhh~#-xt\@{hIZؿI RJ9/",tK 57ݘWp64ҹg@ ylAW !V r,J'2@"P@OC$li/F. X-lB9);Z LٍDbۮ&ݰ]JP'JD PLZ Q)b,GAk D貕@,HJ(UI! :P[LPʂh< 'e4R?=~i ] 5Z FmB+2N,91~5 @gACXA"N9-+3#Uxx6O0mR'PpF+ZF ee Mlcuζᙝrs1Vxo^{)(u }fRk7ۋ/3?(FT/-6Oؿ_xW+=M!:xSF􃿜rOWqÙ&oWl\ɤk. 3б"V l>mG^;HW}xU^F(+cphehX/hCi`.kJ" <}5RߵXz%vi64aj09ͣh.P=eFGcrqlݝ50KWsFb @g:E`̗(ɬpDT.R#MQِF`0>Dӈe?pn|/[t62̮jgx$-x-An:{wf˅?_k*՞xsw,Ӟfg7"'V\kI\{o]D%FƊK^"h}V8n& FkE0 6 13nEy[<62V//1 7Nq ?;>hnhD:eտM%޹z9bYJGk]caz}݌Kza!68ey~Ԛ2EWbfP`<ֈͽl,X\ 91R)M@K)Wz*.Оjzف1(; !x &2a6RP$>W'`$B5 ]HD-ej.a=kc5ֳ\I!# P+@{jFP1:Lu8LySS1B绉P膡dBo <#C+bIf%!+@`)2 lI\ @˪YFc(XvLq%)G~S#o?[*t=˫&E1MΩ5 B EqCyؽxy9q0gDLM$F!bR9=_@$b&&@U>/XanȖ(Q#&gN*z^Z );NGJ$eJz}>Fǘhgų5b-&-DHRLN֙(6"[K^ԊcΑKLexZ$Pbܕ 5ٜ+]Q@|7B( 7>'=P,PT1btqLoo:#]q:Z|9-o>7Gv}שߵ펧O/O޷KW:7^?ﻗA.6r]VY_ hZ@.Of@w~;8F']xnwUO|cܚLnP9(vtM%hDDjs}`dʥx^ae2.W5gAT-b(A= $P=T`*Ab{1&eT88GA7i8$*Cy|#t aw4Ll\¦: lц޺1;dyf-k@!NY$ESEnN4tI6=s)@P@ BD1E1kLM$%\{D*/'lj58ISc*`4 FlUR@{ Qd!R6{>r! .H0};tUh"`Z/'yB΁%dC7埄b+yVAq?bTR1΃bV+Cp}Jv 3O+\46i.Hzt|[^F(xzO h9z@=-?uOO1ԃjKOGI<~gH9ܐքrI\kw6#@TyO禷N IDAT3Z+|)B4LTWNJZκ줗^OZeO^|g+ ystn  T^[?R u_o? 9'GO /?{9P]gVsEGɫװA?2{_l9nZ<L"$^z\rt$΋ѯ\ەuOq ٲr хփLPOF~5'oT Ѫ-ުl s'X7:Sr4D`ydKj7sSq=)L{62*% '✐ cCm@`C< 8O i"9,Ӑ"2d"j/lDC3&""w19t~DQ,E.^dd#ҳ+>sWEckN^1 !`DIl Bk(*`w *c,Ң+bԮ,+by NIfaiI17FiФv;Vy"<@R4"$?a,zDڄ껖i8;)S-(QmjN sd]~!bM17gTxH{=R- 3QM g4FQnm6?<'`9qgX Zx6I@_{P釮h2m?CޞQr}lz<4RnFŁ2&LgȬϝgNޖЌJc[z Oڪ߹gWq eh J!6q8cy(a Q?rS?`e@⳼0!`퓴[yB{/xǾ6[Z˵JH?ճb߫kg|5]|[/'x|‡Mzi'SF T?̙ Yq]JqV.\o&٧h"_v"~Iɣ c=2K;Iz^|lh(ms ,r#"c |PCDб IB׎蒴+I`FSHYœiAe*w5 `)D !#*q!"b&9H@6ۇ?;׽k d-f*YHu'F0.#-8( ,h]2iG h]4/pZva@=Afdp)AJʭMjX vs%0DLwʹ:T>3AFM]w帓s{OUG5cZ+WO%4fL,a{FlAl\G}~v FKw>u _.}tXa1=:cЖo$D$$wk{Is4 Qs#=ֈcLy h{e頹e0pS\'Txy'%;.:qE'.M U݋9fu3wgG[s! iK{9s4zӓ}񌧮/u1gYtu 43Ɨicpҹ+fcA$7[yX Ұy[,V>WRcP磕RrO+>JA`a}h#b(7#u4c֞ds0F3sP8Fn+8zsD-Ѣ {YBfpsgjzspP8BëѐA~d6;*qI(Vܽ(ak[.x.z.rD!h)@[Djם6fͯyŰl6t"IBS±L,- 1R*< ]R.^Զ0*) E QsJh?n/@(D elDclk~JJY%ɻ@e ?eGO~mv肇x_~ccA  dgp*Ͱ䨮ЫW^&(Ep1]?Ns"cږETBzѠ] w9"]Tܻo9ILRqE+1?2ٿpnU ">d ?fn?,F%?f)1DDmPdO}`^ۂMhЫB+,X@h;|s敚V+0 8/u)H_|VBq0C-=S tܒ<1lXˮ*hfM{ p 0**Oy%̟Dk= J;fdGZFǝd)0LMEubTA &zfa;N80p=Ҙ7K1?aL'Ͳ)t)1Nz+T޲ x6"gʫ6Db<%Ztx̣JV'RpFP 9/Aq}k[nmYTGc;Ҟ&s!_j.{"!3Z@e58.wm`WS`@Z3T>>^} /2ȉK{? w芯W\;?~;{N͚֞q~?<{OؚV7&ƠVSnfwcnx/m?{l-v>t#2X!spUsӝ t#1O?p=7~w^gÿO9).e_"KlL/]{O,?QYzkK}99ן|½k˿WxW~p<^/~Yw._xLou5.d"p CS.t dw(+9 w5.^e7S`p{"Zg{"slg{w-ͣ[)wuk|ÝH9"Cה&6zX[_K%oV :0+8%)IvxQ62.lBDGK  1 5-h@*i: x]#='wj~%-\"Fza!4[)u:>*7AA(2kW; v ^ ,%PEė z]V?,8O-+ɭnUQ$wemOdjxnlm)W=o*UN_9D7D &5}2=uL#h8^4PfYv=݂umf2fʡ&7^n= PnZ"Q`>4Ze.9#S~KAVs')H@EdgCj˙GKV+nO6Gİ5c$!{)ROZ#YHd>1‹.LzEfOW2Q*t)2q+MgN֮2D<`e n{3SZjp? 倎44M X3HvgA)j^G`2A$-J_\iغg$҈644 A*jȼTaWpbvlS]hijٽ"x3A@Ik }qt0"-sfUa0P jeF~Qʼn(Kƪ4`,ն>ح &9 u.5u(b])t $Y,aS;)PceOn䪟 ax G$yĹ5Tir\QmϴvVz*QhĀwtEts$i"8ٶ9JY ?-zkJ(o-lgcz]~h49L@rG:ܒܖard7KvO$:Nz dS>S@qq_runlݳkȣ, B]5g6ݶfM}Xp}Svm7.}ȁc.}>i[khL?-8=#TwY1Vv%_,x?G(+4(26nC)_T{C@`tkU팭TqسN[t {@߹w~F؍QS-y ZWH1YrzT3I=Ჟ$ldVq^VnE ;Π6Ib,{>!JLYK,tHRfQ"g1٢rjub&!H2672X9F؜a鞇$-E"(Ƽb*T  gY-'- {*ygJKYIO@`8@EF2YBamG;8ST\ȯghxYWܔciQPEFv+-ڐ,縜~EEm=N,sޟI6׎v^*`F;Oe|7ն% O&i7ٻ.4HEy*/mS'uOANTiWw>*w{ܟ7;lKό=`7r4#Xv~OacF+v{I{7a~.a34N{2|u">DI.zn۝]rعe Oͨ KDȕ_wQJeak.o#mvmJߥ*ց\;(Bg5o߹/ʔIz$9ҒV[HWAHSú4[bR+9&/FUCI TXhG!dMsۍB_Kb21T1*{PO kDIodѾ wkDŕOmv︪M`9-fRα9f{y4c_|)~|WG=N-(յf(lDCWqLwOrr6(qeTCFUܣ zާ6s6X!ɱ(CفSm ?:e>3D}թ(yKk$d:BIޑfbs < rj^Q ~zIf8y pvҍjL;:5_PaD<<7i/b:9tmZ4 os%fd_#O^d!})f ,铵F(3QnT)r;13VJ*sTJ3Iii,a&a9A'# |wKJ:s[8 HQƢ-Ԇ^'ڿ-VkZ0(mFKRk\1Tny>ɶQv;׷nWHz) @Z45QzH>38VHДB@DBPORHXjF5j=JLri~SFKͳ%Vrozp0 1[9 xfm}A7H\d 宊mU_e"p!%E5v^V\S,641Y$f& $.[.>YHb`.5em_[2yf2{5ŮjYsSdeHm>NOr'Ni +ߞIC%zF/z==G]T-p!g`D򛬆$R9O LF}ـ̱f(r>~5l!Ѷ<ڮ'١iq܉VF g1cCk:fiO$!]I@-!M<d;UO1v$nË5Y TE'N u ,5`RJQ֛5B_5lV[J%H-ZC+B:iS(`HsCEM/FX=XW;/YOڪjU!=k|v-q8v I]DTdó}t,vUZ9IBbbuWAHy*Im/j[_AKy@hjּa7ʔu kAYh-=5nݜݳ[64%g(d(#beo@KqTQm2 x }[% MtJ.ageެ6KKIuڸ5 TltZ? FHziN C̾{IJ7$u.qʞgo1PWʢQ:Nb;/i&C`$vGAKA]"vjN9_”"Bz,oM([ء^K{Pdߧ}lu.['Ϲ 凞H) SD׊l^)*c.ͼqlja'͸TqZs15I}jdc$K˱2%HR,<&-%e܍bη'}d(QXhVܬcFKAnwG0K@E߽;"Ⱥ[ ,2!ge0-IHQCC%S X{l$7sД7:]/`Fǩ sMrAOqtuk;8kl .Zg.cDo8w1BnHgԴŷ޳E!_r\}L2is޲ @\0WKdj(Q R:y?Bq&]G|%' j'^"E(ViL(hE'n27D;!Q|> U6sgv5AFCҦɮBbgZT\10ǩ5MG|yٿT>W*Ԃ`>bNSEٴyq@O󙒤FNBΖ.o.IV;cd/V5b)hK$df%N  9WX IjF[M#SZ+!kdY%l֎"=7&RSf$+ jOEca T<5 gb.d|A2z'ђ+ [7!78igv(a"le8[:gE4&hn9_`C3]Q$HAep)-u2@uG[|Tx]~>@g '%C 핃/2PeL7,,je+lu8IQ mn ψZ w#A7>'P˕ᇵV~ʱ*r КN9[9hRM^B闣 K)/w8mJ2Wh%u չYB|^t2vUfZbٺ\ᓕH?~\.(~jzζ=*FF[CgGt[~-~% >ξ u½n?tup1.XVOߖC`tЂR2nR lZ啔FFتF5} ˯J&>Tl$֪KkK5[:ZNL'i*ea%ZSmz/Vrpw'ۥbPfSA G67c 3R\&աY1@9U.X%SłfPy=LSU| G>G11u tp3¯MXF@wHh:\,Fy L-jaaQ<YDkǚc㐛al F@CG yB'pbZ8,%Q3 9KC'Hf`9KFߤ8̼k67ZQ|\:6 BRf eta̟;+h%DF*= Y@ټ@!2kD=M'"截`'tA]Q=ĀPdoJ8M},HHb/_+zgJ:@rDyq(^?{SCڶI)D'*D{#;GE1lUU\:s[lh/@OX)ہyV8?Q4e,pP3VU wƍq[r ˈ7wٓ-{Dů"JVf2V V&;{Hی9)EGVLI y %h|·f:sbV-ۊo7iD:*vA-`v)yd0+t](Saz@>'ijF lO艃.$aY^MN#*VGRڴym>dsʣ%BeH^|L€8;Rb!GtPf1`g̛ V滗qƤ]W㨉Yh4[LA+,جgAYH(Ya$䅼,M&@`@*GVʮlf@xY@%Qٔg ,DQBƜ 2d&#(qQ,Y:d`00k01YnWN2iJJ?kNWδ\b LCeκax+YY͡Vdw2u}{]| >@̃S{JV52M @9(,:)Jt%Y̌%(3:G:iD;/y/Dt`e_??éڟoY43_/^oz> ؽ{Uk;;d>G V5X`2X+( "?yk~`߾U½+DJ`lo1̳S[WUUQ#j\ /P^2c rDVVutV5'T M!p$i%UWikM(/|9[Am}{U5[b'%d%/NeT AFdq0ٽw.UtEóG"0]jfV foqNvgdRtJʼC5`(,B SR V3^D%EEA v$S>Uh{ɴ\&UF+/wט6&I拉\HF_!m'}(TuؘH@$BDӏH3FSpuy32`ZZj;_cGC!!>1 #5Z){ۑta=Ov)-K[mG@=<R2i V҆$AAeK^΁BXG"/ 3LPFsK\!;*{fegS_tzlS"d`0%fZPðv„ə߯_~YPS)/YAڝ K&G7kKL(6%um)5rn؇dMgO T%3݉qsk''6&Y19>n臯y}W\xὙs?}[/s{GS?[O^y8|1uh~o\vohs{*_~:|bs?~j:sYۚnkx8%_w\7~δ0^~5[:\/Øn{ߍw'O\UW1Fw?-xyU}7_q]7~)_7]k~?nS]7~Ol;7_]t}3'҉,mN/ /Zezz1NnjvWw4M ٳN}=\Nb?QjU6Gl1 -:< @ĤU:?uἤLUY[SeiQ4|'5]g$aÙ$7Fw HJ0=5r_տɰ@+S"x- "uI}y uׅyEv9+S=NŘ7<ac h_-֋tdc-%go^Jc-k9 m;0ͯt+gg=7P}LdSF@ࣙSÒel'ÌƟ} R|d- I6w)&@\@ ր3j[v{Uq}PUЁvf"ll9oȓY[~9w|䭗=g.ՏW|=W>Mt IDAT_Exޙ|3~O}/ᩗܳN;/x8ݻwi·=^O[}ڊ9bPeH:~G>|ko:׾VO+?rUuMg>>Z>M<[|לyωK{~.!߾'3?_͟ 4ҏ׽YVӏ=on{9gy~)_͟iagw?kc{?{x8×}Oo8_mMy[ogCn=OGM. w`Z _A]]*Z ji{/|_Y\e14%ߖ/tuj]bvŏJ[fw}A=/yf12XcPac l+i?:0d9@ U8I6Yх>hf;DT"J i5Ѡ6dg_ 2s eb*sN Cmp 1.2Pf(yh@i}vr31Y._Z`{~Y(JNvVgw \Z zs~!@Q8 6ag##27 0##GF@ ͨ6`lRN`*B\UTTqunܗzB1ri )F[Imʚr~UFة)mۼaaQtOɖh7o P}vxm-BeP4DK5&ܬ<8!ؠQL(V6L(zI :ˏP8FY%fN/RPPPpZA>$8)X=L&s3kObcDz2;L5zsÓn]ĥRLra*G)9 n^ax" 6_?.7)=W>c1S~㡏9@ `msrL!޻tٗ=xޭ`֮K.򻮸W\ȌcO\W_| 3 ڙGN,=/DE??zٓ>ry>r#ܿ_O_9v< 85|~ճ=޳gybp|c禑 &5Ai?]|@)J ²9xTpBU uaA@8TZa4,LS lg2،ʛMZ:~]"D?<6s% Gi1N_ b+DBE;2W5)_'?}:rbI/UϹۧ0>vy鉝iurk4n'ƑG wm~ᇾJ[;ήdny9[:=wxmVǃX_qpvƞyCv v뎣%X[ȅ{y=+8w]3:Y4ؿ{GE7pGw-vą{G=y`CGv۵;6-]d*jgS[~S֘ ndQ{ER(rZ֊Uzd}*WZW)7Nd;S#OApY SQ(`6"_g3B%#0qdⲼD|x<1ʉE8ChPB01b]A6sDw!:i&r%.n:m [-|PxdI{¥@ysh76ԨGNecdZNvd$ ف.@uִ{F!Bid,rim;7q9uÊE*$,#"bA֨2Ȧ۔QE'\iLCEÚF4 T ă e5@x H(FtLU ,##<aG"C`uՅux'*!*25Sj byÓ1+^3 ;7E|B9G`$jy:씷%-Q[Mu"c>{Kp&M_Uh*LP ]wsnorQ<"HDVNo}D)HDC)rÅc.{ r;;ާY[Q Y=L{l[ ~kET{nŶ'6ע?*uL4vȬAZmEG)6N(!s# IV{mڙҟ T bA[^ 6˓Qdth5?IbȳOWfMpNVMP;cҷ~sxoؿks8+:vrc;XjF_X-rbrnc <_; a;>sOlNg3=}w_ySrެ"_ЬGWD"@X/=}Mg];~Wy`)z:ڗT/ۏzhΠ+h*'F̅OGgtY{={?_{O.7vۣzg.\~bs/?GS&<ǃٰnFY"fSNKȤ/{}PK>XfE˚؆wy9*&3=rvGSkCaI͘VmFjcVCǷJuEʑmU:RHcFp0(D(:AyxR_ݣNA-Wf* iL!2ČٰpqpSHKn͆Z-bD ̌s!RNN6QCbVP;+P4FƨVOè֨wl;g[uC 44˴9mjj܀"K5 S 'CTZU\0QƈIp@!MF4P"  rMRP̍@Ht`0[АuI"d}\Q 7P n05!7GtOLwnUa ~IU G\e&[/$QK-JZאxnO@JLYo}nߢbqÂ#t+\n#au3iy2I FAJ,R7rEz:XL)lDA%e_~]r?~3^O~|t}+.x'/s|fc2? n!kWgst+߾}k_xnץW\0Hݳ{oz3]{ٯx?vx=SEIf} $Pa'M 5VX h8pξ"pbA=vb^MsĿ| ܽQ!QvY<#7Rli>vf-=Ų9݌3V&iɕ݆ JG%H˺sҷ-kRu;Ķޒ͗--^:&7;$G<(/ ?`>em|7Vw]/-̋n9F:ͼdrKQ [ pH+Z; QWiXno1DžlC/U=Anv4DTcxrrڂ޾|끴<1gTBxa. ć7wr{]U0TxAjk QR(*UI,^Soѓ00qҌVWC+cO?s<$fWfc'e w.0S6J4{k|.Y],3@/X&'i BT;T1!U1NJBt d\~_! z; *V]qy K!G;6qiH'NbkIwNͥSZ 44liTzZUbR4k@TP-CEejU\/|wQ{-HOA&])\. c=yWO;P9qE}ӤyY[կE^H *t5;03Ɲl{ب_U*YygPȨO-ݴ͍AA(S"q-:|QvŤ'[*{YoGx'+ӹ~ & a1[]xa`au:5N3rـ$P[8] gZ79" EOL{D\ <6x*6u@&8!e)ٱ(l=؃QȃIͼ‡'%1T ȍ1hy#S! wı鉋ؘDμyb>*&|VnF.LRDž3 f @̺vעޛg]h܉02z*%`ѿ& zinwm(ܖJ= tCa^V=liqnFo\p \Cp(3j2sGrR GS\i}_Ug2sC$s2Oz*mRh-rnl}}a,з2(]7OrL*mXjTȜkU7*Qht|lq 36*Hb!-p̓E{488pr 4 le5p d5MFDqtS1J\$e䒚gDDDl* TC?3gF%Z*Y IDAT yJ4l6,M)^4|"^<0FY mxu|pc8KX@!BJI#!ז!VƤ[v$jL7.7ft7x)44bgz`5O2swucJH.CE?I;7ѨA&9`y{q X8 FGSL"'1"P\FYHؙ 0b<ᎄI_RT<ь%S"a)eNW8; 'Sl3#qĈQ hvHxIP}d1<" oOznRzSseE3횝zNgyE829!|I2pRԵR-I!םvud6`fh]L%Z4œ Ծ[19Bvݷ-!ggE] *9{ M; 7κ$otTՋm2jh9<ݨnjέt[~+pwX=f$ gG_njUɥ kbf\]^)a掩 uO UCh}'N`Z[Ɇd39de7N-@\u=#93B3сUI_-;itȸ|Pir䌝aÃ8 pB10#:vOnHzI{ِ(k<x=ptu,tEYeq˄o; 2"VM"u\WDtPaZyIS:a"RcL8>&fJPՃQ7+/2H|'(m<)`BE+`Ax7)4_SlxP<&T "rwb?ՓhW&ySIkT3A=y-}wU̹}{aXHA(XXMblyI$o%15XQPQEe{1̹|>#½̙S3Pjܶ@BD\ [MaSF^ \K @,?tSDR ThȩRaĺ3* 9؂\58-w:S.t͊^w\\nsnXvPPa1t1(UuUeGU88R) b(tw* &$*#]DYW)c)θѝ9L-59[vFr|顯@e{~R/ḒVќ8 +G5]p k Ui ^.@2>M?!ASLFZr@3FzVm=U[nF1PbsSjM FUWR~HEt` >Jg)Qh@5R[3q/pL^ēTW %]]-ǂj#pr2DsiB]Z 3trW d!ali Е8q |J`zۧ G"!z̈ h!`X͟jZT&1P$}g 3d#H9e&圥 :i"tw 9Td7L}6_h0>  Dވ81J̹k 5s&n+9<"KIy4G/hRhFd-Ms1CrwsYYrm^nm ҹCrF rUSۙ~thU}ԎVFGsM)r}t<16r~s;J qT8;z9:4*jV`y0b@j$ȰQmXg`"#<! q #V1 UQ:Ojt' !{t,!-@HHpG>DM`CݨzN$.΢t sOKG&P<ᄨ]Xr;F`P󺡞:ۓޔfJ9t1=pᒩB*ۢ 5:$?JY h3 UIIV&^uȁDdjQFW@FM5twU=k歯d}>NZָrxhd yD?S[8 )) hA!EK,28@OʈFu}roN+Zδ]6(Vr.JmM w+? -L. \lIjaT|xXPm&-`P)/bqhGz#2I qK(t\{G]V3Ar"zi=Wx=CMRfvW3#}$΂g}:ʐJfYtJFCJ{T4 {.iJ:{ 2DCyc8+ Xr2NLM'1@ as 4P: HsaaH̞ 6`!"x~ěSr75WPf*asOM"2/0'DlyەA)b'ž (Ux#wIZ]LZ6lC߲ ,> < 8'4l"(ݢRefv'BKqh A@Vڙ"0p.ݬrZ1n斗0S>:ϢspThl&Tsq_PwQŅ0~> ׿wtnL QuTaGͩZДj~5sqꮆ (y4WcVC_{y1rEyi\Rd)\=cSm be_q.%sL".u&dR4ƺyzfyluքNQ1ź{Wse^0-8eW~s`E{SBx ݾp?k2r{-5+'x%}ѩg20J8B_PZőju9FmnL;F $FS;=\U3FFA%ۚ_>|Ō9oOQbN.c3-fE"`LPd )D~!43`MG O=SQNb8C!fMT?%?BC\d2^3#c Y6 qJXߣ*5)٢>n@K,cpi R6唱T1|sCZJ<x IS} x<14OD,, , -B6KyҐ7nSq\eGKֺZ7K @ cVV3SfAf*dz<Kw]v:4Rуe&$drN7hS@ź)$ejĉ>YA a'Hj yw{iZ^7IM3*{ ͵T,hv="[6C*Z%m̆iA &l#E3+4]p:eW cD ^t&`pC]wzook;+b`inʡ4n#9W_*e?9 T?[ރ@L&Gyޑ[fm977d0ܧy[D%:`'ZaG`]qesnҷeױ>Sh7\4+?&Dʻ_*ca nx'6xl?zΠuzuMUel`>VA0ia<3x%;0 : ڈsg|KN@ZA1pt#i%"Db o3 "os4eH#9Ф?ݶO/q2 d$ck,J:v#!ڨRG.%\;zW w#TGyHEv@C 2饒2ds`jE@A#:Yi2D@ 2U<%q-z=y: Qjiـ"c"E/3(b`!tfH+tvì\*N#<lAEbIIQIW~Rsz m| e7@&i%yKȗ~76VI T'!*]Ѯ!kVB"poH[&DWƧ;[?n䂡\{5#0`rҐls$o?Xu}YKa.rÍL}gPCCĝg߫˧G0e ˭}'+Q*yw^A IDAT[2܊- E XPYcNjhB/B^ |ޑ_uiϢt&m+;2^鸁 gHc/޺ eZn]o[a !ZCNڷ6 D :i<'ZKcAd #ެlC"8 w>|Z_%@~>{{z;A5 uR_=ZUxTkУơ{H_HE#y7?TP%ַvDCd6&8H)vA7ogo'' gs׬3/ |s}'o^vL+.kv7><2sN {=bDu߫=/~L% \9vσ~Ż; L)J>-J.2:{Ww_-ˎHrQ{zTQ8JcI_Weӗ׌Wy]^]sf ~9$g*b]>ў3=wpW]Mh2 dيWns\wޒ?<{޲S.:șCN\ҙZ1`黏6:A?OnZ2c s>i4KhLr4cy}ZV[sۛrwAy t=RU,>}hQɄVI>Dh±9[ !]񳽃k BQa,J {8 s-![U&MDݲ nS[gBtLE%(')55 J2Gcb\? (d逃”3N=q8J)W۾Gv[^?g Up" )/Cy`@vL{lD N avv p$ɍ @!o,?ɮ$Jh+ '*N h [wq [/#ZV[ICL:kq/~➧=xCYOnMf`w,:bhKp<$dF sTT! Fx0Y ]J#3GծVJ?cD-X=HD(Dhߙh_ڭ Q$є/wZ?'~wmu~`#J2#P4ф3$MЅ1aFlL} ǂˆ3.JzwVj=o@y{ήd4c |XyKw^w7+ϽfȇiO]5{>1\_VCg)C} MFA2IszߪYvc$&H!Btֲ _:dtYy( rqI6fDHX0 D~JXf>+"p;,"bG43 8m,;X`'ZUj Y:3_?+oT)_m]_-sLYL=u}K;xᚂ`Z>߾3lymE׎mT 3/=cVtLv>6eñ%O=ϔ~"!*;?Jm98g׷ jc=\zIȟz;K/u ^^=-ϼ@7o~>M N~wx)OŦp4?0-w~r?Sџxkv,6c?VOp$qK'}^۳3c[9XsLm;iSŵZ8tˆJi>O?[e3T)V냪}в 9oо͝c_yQg?z{.t`x{UKΫ{wW/*S`g—XD=45:(<Ԡ,M :bθ?tƃCzvµSTWt8U&Twɶa*w)my2];;٬L6?8'ՊK^^~o)nEߒ7ẅ́T /ζ9QLn>4=Zf2[wӾ}oɥC;T֊$4F[S@G OdwB :T; ;Xkix3wMvEJ":_4~ٶI6.>ru}{7c>m}{c׏߻b\qa/_ͻdhݛ;z}[ bi׌# >E@p@q/,uj@Uqs;OU~ӝe˚~96ɜ?_:s&X""|m޸²L}⃹Zc>]!_Ã~dge,  u!6ПhRA(?6]c;<#Gy8qq `G<ԙl+văqCRKeb, v%|,$m]l[#[Me(k/Of6 IPHr۱&3^'y?Z~}g*d1>{[<+Xy`ܫ[F:;.8DЗ(Y~D+KV$hO" [4YG35#X+O۞H2u11%&UZѬ p۔m7Lٷ$.~s˄7OJe=!_;^7=Hn~bS$JӶI;4fpc=B>!u%,s*DXIϯ>dI¢`B}Ͼ5kO=zumѼ-5b{??gKS>f-+e;Ѥ?I?V}[ɡ3.j+۽.<ؓ7ki|73A}<3e̶v}i4'@mu&񠦎Z$0^I:kuJp8g՞ӆ}fb}[FxNiC]8$/ҙtN<ӆhޔ!.񔏡}wج5ϦFSQq8$B9`dxyJwDSDl}ͥn/D>Z6̽ˇVl98){-G~~~ooζmkܹ \S?=8K 7GW{?a͠m?]C[ʻ*Jb&,2 /"wlnzs#UM'}w->ʂ_,o9YGbI=_@Kk~2 w} }Ʋ;$V0#ho 2cu9_ߙL{SY+=Q`җ[osHϫk*=kʰj(۪Y>O2?; ^X>}ѩ ̻\yl蝳vk" x&;-К/glkՕ`!5BON?nCtӴ]WN:Е ;oh/.uZ1/+֏̯ޞst'z/8CD|C4l269-:}PAK Ey>Ɋe݈b!!#"Œ=Sz5['i`]6xWQ6؁ӕ"4O3wO߾#WݫT{)h)dE_\?;S_kgng?:Wu 3{]'NO C? p?{vey~{yu{ W7͋ߟnoYnY6O󶺪[/Oށ:im~ᦿ|~iNj@uӫJ',E~U|^'!@Ne 2q!¢׌c qrx}y{`gn\ \{uZS#bN#d3 8hu}GNzjկiz&}ru%_~8G¼ӕpcE]k (]B V%"JUҮo) *^'Z9r8q"q{ 8'JvWqw\xy#{z|M"^>oN]ʖ7 [ެVe8.?+>7v$j:.%@!`Q}Gqׇ~\YYUP,|~o+ SDxܭzVC{7%<ڍ!J}M '>bޮ8 C?2S]7Ҽo_u?z 8Os_6ThseSTtFl$Ed[IȟĜ IrVXmsm9R}?~4ϫg,o˝o!휳j_߸|'nxohХk_tڃCpeyrť6ϱM#MO7@ͱd3D:XKّ r7N㷯J¿^Weu[§=0$+S\l-9g+ I TZUyJDt8COWַ Oi*,5 D_skt只jի"6\{79vM˗nwoeCZ8yk *xO.ŸڊC>\ ^0n$ܴ 9| C[f־n㉠#&?xƗ?BQtkne\qʈؙVsc38TǮt/X}>,r̝׎ GC5_KZ ݅zFO:\S@xs>,JZcYS8ݞAs';H>emth uxSYof_:xsb-Ze#׮*o-* .VޖQo}1w:ޘ/+S @wfH#`M?]ts>qswG|ڵ߿v罚xꝗzʍG7gSYO֖GJD)/_<.k[Ue`>5ww_^s7$^'pǮ[ dbI$0HndL ęC 6L~k*A` Dt&G<|冗>𽭣fmUidkIQ05ee5ŒPn.zAE<a w󡁛U#kw1KT0^9Hj=7%h󡁟\3kAȟ55l9Ë6%} iҶU Z"pY O[4lκt!% dRɉLVDv0zŘ|>iվaj_Aߒmk:& c>m)XܹcSXbڊ HG7P5n騎j㫑㧸\Ϗ @ IP S^=T% b\WN~X;>QUs{P4]om<lTI9ј>cH<7znzkdmCLi0z2\ W.oqO 1=>bEI_pcMG殼VRO{  H6o1ܙau-%,+ &h6}uhBjl=2c{dZc[xT8jBV@xH,bXMM9GE -ڧ־f2Opُ2ޓ]E+=XЛN'a - vR0(gʋo/3I=7.3J :g[>Rۯn@s<Ȳ1j) @@/=V`Y~AmJ@|~ݜ;p^/}>;?O[z#B?p_LxoD"l*X}ק{}KHf]=%ZG[E(7Kpkhd:hLrij PS7m f\0ode"@pI(",?v߿6Mh h%/֖Dj}oYKWCg2OE! oۺ$:uW D͓PׁH_>A'* o$c? IDAT9±`&ȫ3^7!ol8/QLxηNxk"hsYW~JclJ:k}P{×*o+* &:bטxe`u76Ox`ʢ\u['r΂;sC5uT~>[3p@T(F#n5ukꪁhuLs"Xms׼cZl'iCf><_xyg"Mp߰m8+$opǒ oL 1u?w+4@xu.?$"Gb%8ƀ6ī^˷ y"- % vzӉOݽ֙} {zBuӌ]_P+W| YnGtx-8vr(!=Wg<݁EiXrn =\N/3 C5'R{̈́aZ BIqN\2Y!#\>ǻJs (wڽ(`ʾ W_Geonlhd6{s)Ï5醐?L{Y1@F iӯ\4;bЂ<_K:/!# q͗#F>ūNyђPwAklufQ<-Ѡ3Ϝx0#5d`Y9AeS2}ޗ˙ahzI$//= Fhf*DNuKkNJ3ƸeY Hi.کjƜm>KPbwLgӶtn/01ZѤ?O'dr xi~8|%>ÙxWL6 zFw۱wڰ?8wSA0jԍ"Yoz-WaU{.xwm)ȩ4_ H́ڊhrCCDDFYYd[݀p[yR)ϑhүq;R.Jeͣ:婊0}Աg}$?~=5l;/-?[8C8@lp/qJdҍ"5yOyDYl aDY x BY/3BG>^8c6Yw<pqD(:'xoH"S;pAB8Y4BVr.j&6(1 8 w%޺3] '"bYa^_7~4C6ww.15GG_{+^2xfoJ}^;/>ZvE_I3|S Tk\"7S$KbQ(gAg: ^oc׭y o{Wp@E{CQvSORǥmf\Hsj4F[gʈ^F"{FN‰Chո9m+g5SP`Gީ'ߘ]3㼺>2Ldʐ#Ed{4O?D0賁03;idQμD;o>ͩɷU8zKgVN[}ԢydF"'GʵRQmzh"mιdkçڋ`p^"̦CBѷ9Z: *ZAju4w"haUq[St"qh@D~L,6lPey8Nh"+d1PB%1hKjOx J(`1KfeEM۪:ΛԔXg`QT 8RodwUՙ>kSo\(`a/NbK[L&e&=$3f4{ H/rSz98$x.y>z/m?AAA+޿&k`P>FD)dwq37IdǬW=;+Q=lK#l34=`25ap8 ʌoϿ;3xnuf59F;ZӷcUFxZhD<ՇM|X6Wtfj0uLo5 zJٝ1E=;~2987//NeTsMxGN& @K|]Zt[&Hzx<+H~`dKC5OĊћlIKْCϾed^S]z[OϷ}jo// s-Y'mCjQx ޥJ[٪ZQ8td4?40}O_qw|z>EN׌ ҵ{#m-{$rzgYG]vj!MG[{kֲZ:U˥+ZfcÎ5_~tmɪmzS[M0aG˫02>T7;O6|9Hpǘw77r't'Ox{;s['646e7GJt)T¾cx_^ܸa:`]zSCy䵃ucNܹwҒз?hf|H%}T`P,z[;p;[ǔ)Dmr*͙Z&U 4?άs'1o<΁[w,z>m.USmͧ},:oR?/[x#l-`gyѼgkߗTlΖ\9{7ezW|ܩ[=i+gu?^t$Ǹ} q*:'?W(=Zi*sٓgFDe{.; skϿ;yo}SգJٽ M.4=!Wl{3yە-r]- rb Oc {^^;gO6rDNP'D A]=mw.:ޝNZPLV1M^OC_ rO=V3&t ?bn5&NL6tmWRM/x歃k*+|kv$zq, 6W?{BWt:*C'<۟{p3J7?a' \y~JY5ќzZ~}nU62ut,T2xoΙCfyO-hzu뒵[uï;cp W;j6v.LtUȂރi\:V0Hy}ugN>rƖ[_,uO&B&=◗u j)ہ4fq̯՛͓~nx͔{5ZO,?Вw4kPAR]47a|!|N@ע ӟ=R9ٕ zlJ:E$D|h^q[&lk=~ȧ?{›/rP|һ[! TdםMAB>r?|z(͗>yڬx+[?wקwmё#N_4cp`˽j1J[u&Ԯ9zs>w ƍn6-N?bd)3 2mqݝz g. :J}yYo|}:v eazT,\lq7EәO>dx4wK.9b o|yf#o --U3y/\_xVnxn63rʘM{I ([ IdJѮ@1L\B#^qo͖>tY##߻/L6zy_xd$Df\+#R+dfo[̫Z.ÖVs ɽ%>qEgp‚.=rٳ7m 9b Rb&v §~rS_?;cD`TEU2@ԔbؼQ("Qx_G3_l˕W~z큞| w引-z\m=Ee$NNT\uT$# CTA[r5 Sd0gn +p˹o}W}jgl{:4%[B[:g*_s=u5G/9~'I9bd㨏eR4V$4G*!">f6q?\I;Gs']5;[=|Ew^'~ĕLw,?RNx;v޻tޟ_=2XIXn17Ic:[+7M1 : +u7ϝ yb^}חqՖ͋L>ΟyCq\[=L-v$V`ɳo@0z-"ZG\ ~TTnʃk6p[h1 xڮ9O#tn-qN֐+ᄅ׍ogj IDATzΘNZJӗH2Bl,蓇u?_%-ʝ_o[oRw74a\[Th.OןyÉV*o+_}Mm|W{l+nx6!p5Ot+E_YѥY=m|[r寝/ͻcԀ?>0m w|_r@Vd&B[]+V~?k{{$=y'Z-QKgFѫ5`/=FBp[;vVk%riӐ6K.&Og.>՗]͍d eMRkJ6uP*8̓źq4 U[j_ѩ*tHmZP,Bt2WOy}jA'"*%z95@$ P0CJCUoFB_M4bbat0]. 0C22""ۛdG&%TQ1G!.V03M)pw6ocY7:Kn|p+I"H )YJ2ѸfS1b %Z'~8H!"a҅PPqh8UXAePGK|x;_ k7VǗYzۅ M͆*Q (HJ}H!"PD GP{eH.dwJSPè^9dcO}o?i[vwcǽaɛNXגT6ВC vgh%`ي0j'Ǽf_d0H'z * !0炐 )HY"QaL%.PKceD!R'5!9=lVԋ& R2(hZgVSiӏթ4\>ŘDSwy H ,R&٧`V>!"P0u彲lfƵ :P/ۊ$r`4P3K^ƲyriHϮ=M( S14`%DĤ#A`!`Hfb"vMFI$Z0Z*T*fG0/29ΦGznP2jOt^ޖDJfM˛ 1[:48Όr܇`y 80 v*f3{[5zc609g ]yw<,0,Ibb o+޼w6Na;=xH?L@(j3'X7s'HU)nmUA}@`Jt:&Ɛ w/w}J}z=~Ytuh ~^c& B`{s~'0X+ GaڑYX7QKՈh\:&3=Fiζ 1zF=ښ S8(A9>]3BTe3R7?I#D(HmRTFjEjrW#HIRMm FuD9;MV)f$2A֑G{:%@9;jsY HBEțkhAl?rf+o{),%" $ :{wr6?3ps*W?XԀA Bm]4avќT sJ@6uC:sڏ~ʝ+?^k߱,,L#L%2 H 4j/n3HR-R Ȉ0i! fԔbW0 V88iB@}T W_O?ûckR:soAD[#҅ },%(4d!80f ȞƦ`:@6+'_6ϯiɧk 26=fȿ'.GI9#('7>8+sۃd4( Egp)vŔs'&]ơc[ GBA&?ţˬ(}E(%NG]b01u6%R"lMjW6L3A.A~֚ -v) =%BnѥGWҚI[hK$,!#bHPT5٪@v̾ Kbs_kyO@g @"TH$GA. AmOkjtk;?HFlR4~ۓoP*JC6QI#QIP8Ij D$Yؒ trQ}s)  Ɉ-@9kZ0hd)A`I ! D2X#BMp֪3@b79yw<ҋ9d!vsb:uI,6j#&ur?TO>4aJ2Il-PF,|-vvZ*:Ć섍^P4"O <4h <BpR,ƦD\h2&pS%6LaQDrzПҷ*mC^-  BD9M9_zb7v7yaolf(31bs<67TVkT h]8ElcAj;]dI;#Hb&?'yfl覾LP8IABAHPIHSp8Ldy'tܩז4X ;@Ԍt֞Z)GҘo/RD1{%$7a.et_S^Q<E*̩L663)֭p3MC0#b dE ZLAu=1 c{η7^!wLY:ZYZXHpV5\JBGTH.,^| $xxrod C^OKEH*%L=7b ;P$6dIr,ifZ}{gm}wRj).Uɣ}m ۭ8ٟ|p6(doOl׮._]4BC8?뎺DudsB Nu%{0׏X[8 =7 В)8ӍKM\nܺ?ʞxJ&[uhfӌ@l|緇yى?=S6oe W%@2iU7~Hź1˞sor1x,g9{++y+L7G+HI.p1)3V[4!b:ӯ"uVtz& l /"u!ύ _c;\GpM"l骲CR̎`}]Cߊ_FceTiM+ RAJjm@D:"g<wY `@(v{Wǎ&1rT֒s4Nw`=/H^LXW[B̌MV3IG@ faP̒!#0`,%-6Pa!Rٱ,ޢ$ 4"lB=`7    ԖÂ:Ojg-}S-PC' ~%Nśyk?s&PD1$QW T2ÓR RMDd/pX3.3+@VW-|12ĵMy8$AD3WZk Ѽ (c׽9O@5%}jYyJҿt:5>97I{twZ}ti^B5] BfkN-&vtv6vchؾ`UTݐy$$Ա۞Ley8#H#֜mMs rԬY%̞| 3 Uh4SЈ/|cn4_ ]>&ѭ(ak{k'fj?jQ£K{Ջ/8A`dPߛ?9}cS0̰ٷnڏ٩7.DYz~E  ` HYf"NLZ$uE38EDs!70`D]\WS6Bfz(6+bH,+17i40rF>SoKTN|M`V*PJ6u[' c$!@$DΜ*H$o;'DHB2B PVt$WaKe,QK.jK 2ͤ_1e5B8Ȱ7lMUUFIakl HN$DDTc.3I&sA&&"$T$mdIz!f "p p!^Le_j -5:idvQZx=e/Zvd#0[Z+\a uT E4S2-$*BRlntˌ fwzķiZ!P&T錀Eb+"$(%)@B 5'\z)f 3fdŤD|+.WuYoQăR pX1w]RfeYs a'c醘uU\p9l7HOh̠li?eM[@HŏCR<9641Yz?+Ǻ|'ÝT<_Ȼ]7,|8n:ac6 xA*9&+!ĠQ%64iuʙB7׫7'mfd.`m.d"{ ܺ|mx%as`iK:Cf D eDЈDj#l㈁ a T$ ™}3\F:QSoVQQ# \t ֯#;ĜqLإR|v*SIOE˛: Yloj .  Ff(9Wfj+l%H6S>*Bb8X ҕEcR|WKAY%n' [LԞ raYy?0&]V6cc&ܖ\R @iX&i`MXJ+RlCF`FTAU1mQk:iDQZ#8J j&% Q@AAd0>$JLjYۡǣ]?l^^0"Ňu;+Q"#0 d;@٤ؘA!Yh3:R-Tez$huHv "֊Ɨz6BG.֕`$ ) J!d@ A4}&sp*Mp!sHҤlld"c띬Ej?kh3Y8IVPcSfKm8ЯW;D K1@h}QGzR?탶q"D: qp7Ǝ>kOT's@K@s/PTN}ATw'8|%I T,u5WSYs[xT쪢PT%,[ਿ;hR'uGsÌ>c\_&Q]^2L==uWZT +<G'IQz.bj1tK*%,F{X$_9=8R'cmgq׬ctMYf%d1b'y/c^K-;i&im:^kK_a?hdA363 =d箏K#֘3]6IeZ~xx-ƬO&Fݍp!Jq:0TzO8'f_ҐFFucGPDqvä㎯>q`웕i߂[Zi3f >|siES!i6F L5\b*̱Ԯg(dfi< Ӣsg>DgGy!(!2CBM1=jvi9(OaϢ-d ֣uޖ #=;dZ=#rݑP$E5bIZ8RilF2|GzlP 1xm X@ TLHVFjۦșQ]=J!i3İS$ 'c`20OٴIĬs (hĆ> q  0Xa@2VxXA0HCԟP OZ[sՔjK)!L|CddLUfp)@kmQU%0? Ɉ"LUPhRt[^H.p.DKH#(7,! lVs"NZV,c& \iNQ H D*ҡHA( !*|mCӞIpbeh4ӷ/Nz Vd*Yd Ne2|7W1 @6*% ,؆Q^rᲛ!QsڊƼPC @)Y'q XH꼇~شFnBbSӯ;ܪH"==zsLlCNɣo&`HlY.y&O1ϣ$$A5157H~p~laGs &[uO=ZG_3W|-QkEm]㏦;Rr Wg 킟~v lL޿ڞzg|g-=s޺q#'Uk}ksf_^v89j?_\y\}~{JI?w=?򆈿+8= օ> ut?Jg wWn Әqkoң?΅(_S6V ZL|?J^u-Eh[w.W,&8&Eo}9|lѽ۲NzD㬂wKsn|l}IY4 <|ɧ)RᵏWvF"ߺ9Sp۹7_ۺ~xv6*ɂÜ~ҼDD'^s=ADx3Yq/9جh1p=rwF khK\;F$c oԦ|*$۲Ʌ*F@"·{~m1f;yc?|f̷ž]S.q' J Fy/ `Wii72M1WhFLaDMPT/{b8m%55")"""Ho'[j!4= pZfjsZRNf8q_ sҖnM#/1}Ћ6PdBMA)X"Ifƨd6hmjl*q|DhQq37S| V'#e ABJi3;P%9Q 0#"Smbľef,]kL` {|p^tA5JrN_d@lQӛ` ۣ^] &NN[$+p(xX?@d,t%0ab⪰NA9fa+y$_TpL*y^;X%fFfF1reC:K3#3~6Y×F(ڰjY3/fuW!iX.^}038kpͧjK^'1 {혖m7<<3 rhzƄ">¸n@!_(e ~ 9sR]>t;'،+QϩrR%n(f}cc3.X1P2L(dS1L1:Qİd råL)# Т5Yvۅ/SVm,ar\e|]~*|#ãB9S( ɿ;BGZ0X|?p9@=Co}j~?{W}w(썏.=('zov# _{ݙgL<=91 DR ҅R ķT۲OUO|o2՗QnD|)+[rnhO)xjŁ'ចs7vLjVb9I4 bR پ\:[EGRp4+յB)ДV`SwǺc0%W>aGXpDPug,kVSW|8/?;zctӵO~w罽q"Jь?oH)Tʦqm/\ܙg=T<[:f[/[ :롓{kuIJ-r7[%}555g(Ӿv8ASvK}\1l'뷏h¾'W̼9g[3ػ{}p![CJD^3#M"P_]'0q[UV9F IL )l BaARF)ٙ TJ~ȇ]%.[ordlڣhK!  Q%o5ԾVG (b)jD5IjfdvGTdR QŪT@K5l٬,jZBB C(D6e#-rj'GuXj3 z+zHD%T!-h (H%M r5lܶiדh랭6H,ɽ *La==9ۻWu,@`UH: ! ̮&A6<%7lA k=Ǧ#HRn5})-P\ILST5~֌yͿ3 (/Nw9boIP0 .3aIGwk͋͘lFcLހD_wun}ԧ'x/#9[uTHBaSBT6SfPJ5'l72n☡Oog}w~;A{~䧖zC&` ^|{\\6U齟EI.sCg[h4[zur9?j؁]ΪE'RK< WMQ9~˸Ic>yԚ>ql՜%lnoʔ%{[m_#NI ~mikNP nA5bcR抛.ɦ? ^~?lTH9zXtd)'ц]cok *erie'珼Nv- \p;_;oѯ8ߧk=M~|ߩLuYe;4cR;M=m)f˸ݝ0lIuG])3AJR ؔ]b>vg{o}QcǿO3?,_OJqѫ~_?y ?i/{6UEC coꬄ2Q6 $ *!Bãu/<1\۞}R5 CWWn}ؗM1|.cWlKU?_U*ՀӶW~̱ϯ?;{E!~씛ο( ͊j%֮MOI*fUvU.}mizdDͼ k{k8ǻ~.9q4f򬑫oWuRe{^"e(dhf z&v3?mk27&ŷ9ɶ{^lM$=^'~rd'L=ڮo\R12Am(|D+ʢdh22c_b&pKK\߼bJsTu$r4"m "%j* (H" k".4ɔQYRtdTKJƐ >} @3*n&T:Itі5#U讠h:ǺkiE12M*6bsʵĉIrՁ(O*LmTh~"Rf Jj)UMb`#13CeJA%Pe;?z@_s~=X6͛02^M$5ZIswo{Qv*XPGqu,'=3^) &]6v>’əl!/>{9c]]~6>^{??G>pc ғRMv.̫{ſ}ϫzQ>wR9r4kfek kޱvzyC4XᬤJ:M$ `o_D[>:U[ 6͊e`zaM ǂ#$p4[\›*ӹ&W 1g+H;v;FYS5OTJ=QYE$4dfad -TJ!#ItӮX47Y#ܕBxVLۇy2ӒXo3H3h3"Q>'^D۬zKLR ,xP`kNR!%@!qA ,L$ʘ!r\d1bOR,C$/kßϾ6_X;n e:^*rz+-BѫDDVsW&10'XUeyrr:cNGBzMLU$IN& ۺ=5%JKڙ}ۗFjeю?Y#O87_lh./9iaX%Ӎt߯]yd]L,MoQԷY`%y@T}晀h`~ğoz| Bf$wo%5Zo׽O.tSf9&ڈU$(c?mƱI0.P/{c,3z^}~ߩKu?>&EI6ok"L7Pξ(v5v kz^9{`DH71go4DvGƋ4So)ʃA̦ PRgcv $"$#Qt>_`g@=g)Y(0\lR٢JBYسe93*R2 e!iZ. @ Z(q-zG+tn/1mꮠM`0MIn2`m'-L\0]nȑ:S]"%Y[Es$v]؝쑗5J yzCd(!M@ @ DjY aۦy-#0g(Ja/cP.f=Nt[qk܇"'*I0D@!ݚ9.^`A-#Ixvi(9 LJBɧLH ]Q$MnR2Co'NsmD~rʘ9f%H!A*"Te44]7ic1qeټ0{| FϷt:߂=Қ#+ 983;aepX(!S_dH:O#zYL @2O,eL1Ĵ% ZW"CD&e$ |TGg_ēt@ag:yS{7t,[{{EAYRHsڷ v>p`=z6l2SԶ)uVq'[qh{DA)'ͱ/7S~nɱVeԇOм8(ls5an\>պW2 k_8wYK\$ E+;pɶKpPƁwlu5߻Ǽގ25XDʭ/_Aց[d&{HҜ*(} cpǚ"q5`6K{(cm[?ykÎ =vlnI+4D,^+Ҋ~)=p3\0'/f4c4h6ڵdMC=[Fz77/RoGehb t~6wă^jIqwkpT=;pVNJeK4Ý "_@[Qo\+rX&&!π`BOB";':[` $D,98/u&IxaЪJ `m9-pYhIc `;N`t &,*o rxnm yz,#mԋIkw6F`(44(4*Zuq6Il@r`" M``vO`RGLU73B̆d1;33N]L\;5 w9?J~ G' ͍B(5QZ$&ITB 3Kv53CL3N X:EPB~ ~y%zo, % ib06hF^m By .Ph= h,_hzN>>Ok|G[荐!JF\){5z)9n9;$|P*|MxڍPIgZ"d{K,J1%pSmW)N\102Y顃VJ4S3hۉׂ=Y^F'W߳g]NY҅'ΒBBH/_~zQEs Q[8/>tqOƓpqOgA+~%K" 1jUtю{/\x$/ɤyl>:e2eUQj#g_[ޕOU^]\.ڱn/q@p߼MYOho\ F&Wݳc{юw},ؽo_|ϊYZ8u kbxJ,Lbe|Ni ֘j:y>f햑 s]3{{s޴׋9auj*,y{5SG7<cG^uOg)wTZf"}7N_=W>vw.BzKK'g' }TLs]ZEށO hw- r B%@"/Cl %8%AkgNX12 YxJDCu{l=Ző%+xZ1qxtS":FO14`4e6`ڠmfL`35(ͳj]t*}^7E+f@'&9""N '0@NA[vLaH9h&4Ml {,;gM7c80.Br&F;fsB5lsRRIҶ$H+iVQijJk!$"{Ȁ4Be0k:a5(lb@:K- M#Ap'.kFCɩ@&^4=K0lZz>瘢?凼/+j.(~"G7XZ`I`U6;,;˸:|UR7{G࿒'쮶F+Y09H6I g}XJ(AgqVc&Oo'g*_^x_x5>+%Wսij"O7nE%nk'^ZҔseʇBbz\nM"e ?tȶ.cx]_~QWV4>dx>Slov8m|xy}ST\#R5 vM!sn )먛ȘA(8}O9?|:@yѩZEįϹ# ƒy#/geOދ K:}Uv~~j)Jx/&ToϺo9ߴ8v|&۳Y7e?w] iNʈU#xO *i%[^2o|jYQz]pMF. h= 7R]օ mr1b tݬ)%He 7RYscd& 5"EeW5iiM脘`R`ٷDፚ liXv F5ᮌ`;xpL46|Қ qk62rAԠY[-kEly 5ADUEyLX F6@T' Y̜q`H5&n!g[^8 L{)>M ͐"f{; %GHV\$B` 6A;~"-.vi[: ]U opHIvG`@w4J\դ셃\淄 8-QN-^9~aVoI/o 5[X.)L҄*9WS.@*tK)N=Rٚ(BNhÌnA-~*i6{ȷ7f[5O<q_yZ|a.8q޲?85Yϔ즷&?Þ4g}Ãߛ%z`'|>ޯ?\(Bn>!lst֮p'}~y=OݢqNNAtJ]Nd!egt "x?ϪV$?*+'4qlMO['^OeYxU:ٛsdѕ]>t((]85Gyh5kVUF#=YKOBr@v&ܩ܁[ 6)8S`13韌YlAڥTll4A31!g.2ڲJ{еF_gU057G0 < t v0eѶ"NEކ&܅;DwfLCܴ"aPt0Dmu#s"KymJۄ3 SUYu%" )BLdF9&mVu6s agl1>B2=n­!h:2H63hՖRLRPv&pW+ 725ka#[LweGںmIXs|bi%8;*75{FO坴ag%Yl 5t9I}Z#D {!n'sd"3sǯ.k`yM;zŃxJ!FnUJc`Gt(O8ioכ Q6D/e Y2A>l  [܊0O!%oo"7%Ld\kfweYH_Qr{PFs%ovmU휝Ò%w(J3 ::-5A\>IFTıi!-.GX!#G9FKؗ~ӛFV͡6N3IۭaNbidB썞[=L4/d O:H“fSx(MLj+r62? uǙc1q\p-K 7o,  ܙ-eO~ ͢-wD1*o34L ٮ},@f4m*mY׺󾮪x`PBܕ6@mBHd+("mW \K[Av#=8>;J%W+ Dv7)^8.ڟ#gyT8myĖ) "29$ (MLM!gJ !mmf3+km;N}([M>$IuJE- P[u7+mlBTa -"ILU M\'&ո ־8]q!;NQΨ M&.܊`fB H4kJR* tnuZ%R3$$;!PHH1~a-D*rjuL.@„J(_jP~h!/~`C?t>nn/znjnBfsKO> U7qսGLW *x?뼅.`Ad4O"{vNZsF0> 0@*,~ǯRÚ'ލ#67/hS'a_H>s~$4a3l!~-k"3E&U! Z#Fk4fJ3s؋7rbjm\z7孇>kOj MB j KvO0ZR>n?Ly˼(lr3aQ&Ya7jrN1V ( . ANjYRM+m":jy_gq+ߜE EyteHR$',Yͬ8ga'Cicw)%@#&K Zk@`mqFwMzf)㮸VwC3sZL(IS"£=;<5sN4 J["Mh |#oHSz)6~x#:&# kM BnNwg(ՀZP *&\ ȵ"G1Z9RRl'Df 2 X%DR D_ σi%BG\(i*Ǫ4rrV#D85D̃Sy {6n0YL>ڇFۥ׫ .8-stIEہŁ}YR00d?hڸ}4$@AT48֑aw8d dNT#m6L Mptdy=U-oلlAo0zH+#d/U JMg*q ̎Y SoT AgP`3v́݌C{ͅx @"=u7FXL N#`h pIFαEy6F ƨ`Fd@<=vd4& arrX)"DS^Q \ E ʭW$%؝|9:[`/XF]uD+* "F7329sJrxx$Uiy-hjkF+ N o4IʗwMҙƍcdPToKR7;qZv[DiT)װmG&pNڃZ:cTʮŒ]΢?/%.\[|eɴ%.ڢ0$iyK]7Vl]qab|[:b8ODar0 زH.xy 0ڬ7JU &r`H'M4ꔤ ŕtQ8|gGs632oxWSe%jXjSHyLi<(T1.39g 39W2cOag-ݐp6O#h ҀH>E΁n4M.3L]"&YI"= uA̙B{&m,ВZJNÉk& h44KJRLjc^OvrVMAktVP% O`&Nx)Q(#qXļS]涑"Lx?;)tNF썤 M#"rel$Prh\a`\ bEv3+r,-T 3VDawlέxJld0%tp;-"s9]_dD^.MU@fL7sWB 9?cqꊷݔ*iilM²R5l[`Q+BB\vκai&63uK[C0Q)l2ER\$J\芣򉂊}jP]>E,q4píJ)3I[X"1 jz%)xY9!Gy9a7 F{C$a+@Gji:[Mp:0eKn@Td(r2,o6G6\iNJK[QY/_yؼ$xdixQTJ^U橢 ?/+LGvu}|Bp'%X~ଏ8jgn%Y#o4WAA 0lAVk&D&^BB u)Q0dɒۊ:QC)WDyr"j.Ff- BVDy0q€bnE$oӶJh&hJT$Y$*RݵƼ*\NAfjZƝ lxF1Z6f ) NtVjEA`R0$HGn(MHkMSQc] YVr  Ux鬌a'Dl#fP(]:MUBTh Dӹ1.E}Ea s= A\}`B]@H%f* uueDar8(U]fk@,Y* {Ц,%HSBtH"rH$y7A!UJiNSkaaK*!޲ Qj2tZ6qO ])oD0k H?H&y]T \t# bjnXg# ƛd%}M'h\e H,pB "NJ[ς \}hv/ef~qVXġ%'ܜU>STR&44y7EtnVy"~ G𓋚[DphfD VL3wC`3J#!"5ʢo&3";1Yiƾ bPSogT{E \y_j!Yd)Y++B5E-AFil߁A! d%lg=qƜo`MU$J22TRL>"8͒ ]_@)V~*zVA{匙96X3#t0n&.:v4D=Ubr}Ga=P>v|DޭXELKfq$`OU 99%>\Z"%$= G cHmLpȀ-6 %`m^Ղjrܸ0V#f9ZVpFB̧d5ǏD|Sy0\!%XUur$gaf9sgc cJܜ|C Jŋ4VhPQ:z'[ľw"‹u7^ƘIrBY)Q5.t>MOս Y隔cm5eəth XrJ4$Đ2@m3-u+rW(p 3N΅hNd{R45 $a&hyyp 3T?%9Zݾ \%LeXSQcT4Ew55QԔKfxTg5i1G)!T(>40$oBoT C4N3%ն,9=04" īvbPMZ 6Af9c( e22I;3@Nd0'Ps,O=:*95 2a0?!"f3LpI9u\: U'yb,MQ b[1BO܌A~˳`'ސ:,5XSA(L>b] WQ`-aEc_k  ^/̨]nJxtjl`DQ BR2 p]/{XҪRSXzH1yX˥+1WEO)GNYFȇ.4$IO܇SlvЪdi{_z Qr(G&V;{%B:kݳ,W'X{&㏿v鞼~L㾧r2C){n?g[q݃͏,p]矽fNdv5<~7޵]9ء'1mCH#hNlL$u]~(ߍ"͚XRnVt`E-,`d '|DJ}*<5NT2O@af*%֊Sdb6}y+;8WsR94*giF+Յ}$T|m4]=|b}e nUO>%}"$ʞi'2>j%BzZq\<%C;isi"P Z3h ==NWTNF4)8a @[O]ksI=ߧW½>wn7,sJiuF>ys:'{71]w3{9TJ\}[k>**QfA]Bh\mSys?9DN#̑ln~9omƏRUҟ{+=~?p o"N+*qT;PͨM'ӹ/9u/wc(]]v9jOyV/}}PtG($#5}7}!ˌ`D2b[*6Зb'*a?|a}_yY_c<.R G` 0jb^h- @U*EGWꂣq,$2\qvg<)/B%,1v44FGy`c90fƬI5'(ap!qn#Lb=ٕxq %P%'eEQL7z䐲} ^/fTDwDJ5 N.C.+;gk2 L^lr+ep !eno`%4gsq*~OGqB=B ˹\gn*.p!lR ^d_߾7ް_^Lz]Ck=?/-n*eC惽o)=lDVi|7ޱz,V&N$[@cv̬}?|UwYz[oHq8p@e7޾zlaF>81u'fW=jƍ;zxq.^J8鱠hggϭ:<ɤxO{O~}g_ʶz#%wQut83KO(rC9]i O;r+3GO{򖾟u<ȥkNyrX[8ɁhT"]Wozǿ|^Gm_q%G{݉WgJyǹA핤М[Dn93~q[?x]?<[ͻ|ק]uItӇ ',{C+-+|ji[>Ϯ2VOG{KL~fFZ u]&]ы\'.L[HN rxvT$N# GvTȻzSh ~ -rBL!U=&/xt#C4<T,a?me\/)ZRHD̩BNjOWSf;n6*jN@36G>Dm#wT sjh$4W)@{-Ci57aBC9kH5a)[~S[ٴr Q-ƙĒE4 l1΂'d/;)Q@.5; InE@.ǝ-hN6;!q^QOxb] \L #ͩ h|'hrMCJjy R+0C8 Yvtoojdhf-IJT s 2MXcI!2W;qi^X.f)jYp^j2k OW&f*[55u 7?rВ ޼^K [VW"Kbn6N~JYR7`˻~LbбjD*|~gl~E ws~to9{ϗCܹf?F~j"/iRWOû1=]ϖKs`wn>5$:nR8u _;,\`TnA.xӚzI(֋A`5|\۾;.ǟ+z IDATaL[5n)Uoկ7:׼}DΌ;ް/t,H3#{ B%%F4I3(M5ɍ3@6 quZ:6,"وmoTǦ#5ku}l !fuLNWo_nKaMI<1*הʟIB։,L4MIqVi4-Yk%@0yΏ&T,aHI{`?pCd5WUke6,hqHh$8T$ `GM,okb-扉-3Re*!qz}.I5˴E(NM Ӝ"Ԑ6l$,En=~vfk$ JI`۹x'kmgD2L#aFco;z[rWDŸJ23 ,%h$ 9{~/>aM`3jϙ|EePw:0bHAƬCi 9pJ ;޹QZЮ \U ] .=&LCue;-C&" +]HhIkv\3 @Y0~o!N/N??(;paY3DHM~$eΡ-RW~O.afjE^xXTjwİT Zk#mF22^`h}u>}{qX[gߺjG'?xȕ=nl MOO~lÓ3ڗw/Җ>v\e|CueW>eլt]~ &*E+8'2iG4j}?po#o]70".̯z▾=@{O_%/:~GW\fZNտt+~t#>mUgkV>ƿ|vS_-{+Ξ1sow}6_Z_pyxr&YxO^b `lKH^Yז?i;7{{q/]}3;|Uvſ*&g?w13 V mkmqWy[%詫[?:YC{le7O0b㗽ryeWSɇxuP߶`,ۭ`}^\&IGoWی+n=nlu};FO89$Qkǟ6Y9\vi/qkh^.=cQ6OVi\'.XvqƁ8' JB`gaJxU-_{dhmkgVzz {j{mO߼id3SD|ſNm"5ElAXdHF&!^R'rwchGwLBc_6̓=\~Ɓ= }mp+s&G:WqLj*%,qWt>z~?gλ7ד.eﻣzʼPo[ꮵvT{, Ti} .s7E_+/?.4>1C)\zԿ^u/z供?;uM3/X~|eWo??{_If^K<}ꋿ8]&M9/o{5ĕx=oz Ƨ+ OWkƿ]{v?MճzLLW^{%&Mn7?vmC]w㶡 V}i55S.~E̘jӏz3޻tms?=`W|\yK_k oom>q>:pٙw+I`Qe?} \ry㸧>s} wi钾/ZʯNzqӼ/8~~IQxu澰e@Z s-'vQ_`xe_?pEz7>vˋ/oYZ솅v_}.pwܓ_Oۑn»?oGl}'w\#o}g[a9G?;OoHƿt|7>991(6L8$YxSC~{O{mfyWzzYK~4o;eGVLLg?8vh!ow~x㻏uq\}Skӧz?<ގ]U{f@HQ&AvFEmŶ}h׭>EEVIB BBH srss霪Ǫst_}9Nծk땹Brfu݇NxXN]ic_tNMh@ʨİ,&f=Aކ+. S0"IF )HP%)$T^T,rXDH%2LHy(P* W%K 3-5_-lضU5VX7A"(T l!!An-ڊ$E?~!_2J(48{q <=F4wuY)QLAXRqCQhR5 XnZru+Ծ)߈A(zCshWL`{ 3]=r ;w^)S ,B" tS%3)D[YDjk=*pw!IYJp6 NJN 1-|;̄ ~}.oݒiTePYJ\+y*n,x"U76 0 ۮz墁47P;g|6jcn% ! (6!=2ra, ~a}}$mZDf*`Sdǔy{ڍ3n3}%Ӹr36ر+,b_w/Z5 `=] ~}8x#{)E .\tpNҠ I*{{-u ^pk~;7e\GO_c^苳巏,8fpWWk.#v߈[iJk^uq[Krgo3@}C}VJ`8$a=ouzz/}|ʘZ[FODoȋseqozx|Ӭ]KYcsq/g>LnytU2]՘ޡR*Egޞf,h\vэszu`*<؀y":FSa4z/xrI}Ϳ\}⦇tdQa: CM^e"t`0sX{İ3"ik[#Mڔ_D Հ̨B (dF"2R@P{2@j7iXRKgtVKGSm@j ܹ`#:(BZ v^Zwtc[&*@ HrM*1$v>VF3fY"TMBѰ)u(>?,b3'ÖA 7१6QW=:u"զzzx+QG g<椙{d 7MbwC) uX,WqPЇZ/ DBH *,DLH# 5oݗVlV2"MM.THnS nE FDY $Y<SFL^v^2y't%I ,ޙ L,-Grn(3g_ g~-.%2+Ol~=7tl3ZyK^{pnqÛGB.; ['OEO:ݻ6cwꇗMۿpjfq}FGP1:~j2ڤO ̝t0:e42RF*Wo~ߞ 1S~O}guqoxsؖzdZʣFh\QpI`==}c30w x!3VW `1ha!! LaJ )b AgRBt3Yz1Io N m^%jWѽ ID)@mW5-T=c_k'o܏6dtc٘zꛫG 0O+Hv6D*ſ~sc&4a߭9çO>Vgۗqua\G_ɳ_i枃wYg %їGa "{dOam3nhQ5'mPbDkv%RP/?œ#O>;;vtxQoۛF.=啅{>ehNlxb_֬:yăjڎ5̪;t+_dWv~E_<47D7\7tv_u=&tG^}ϭ}m-J߽/εL%mf`s[Oyʑomޥ3X~ra_ͻSL:Xk;:3]zl65k M7wo9{W~]Ίߟz{g8u0zU"ªS @zBQuy;jx^lwՇ{,0H$h 8;2GygM:f ڪ"Q^//ݸkteNh|Y9`O?,G{@ۗ~sVfNY|wYdEg˸XY =6(\Vs6jM'f&|*ܣ-&#QADfnݛIQ&XY $ҨZ%ȌR|T+ Y;tidM}IV[<;Jl/  ٤!B m{$^(h)w@pjeK'ڸnM%Wb"Y$"Jâ(6#ac9DM&l|VdiUm,4k'`3*fiUk j" 'דؐcd,MeYF4GٌیkU8ZPIm[jxU,r'kC+"=UHX#P(( =8@)ص1m7*sIwаVww}ڷsWD(HRNUUɶ竵JpU:!F:ւ;\xpe ČY`'ʎz-?cg[y8Wg5DtP6o4񥧼cyƄ=-ij6\;25ް仟Wc-lbGP7OϮ]y]_V dbP!4T;i8Ӥ.8lBw)Ufqkf L.i/9iR0e[g `k.x.M>go>R/5m}c{|2y_YH^nZGHA sHKFfuo`o?{uzk~H5,i1{Ow»K3.\N<|NJ5 ԙ̎{}67\k.⢻u]NuhΎ#(Eq@ޞ{zZRI©1s;K)wqֶƑ+N׾6 ̙YM- ~ 0hYcrdu쫦&x DE<.8+{p2(57kg `Za.h 4GL_O|i$ a:ul_.}.iǁwg `mO=X {XLez? d!.d`u\auռK!lt@4 z/& IDAT% AB@ 7ܺKOjۖBK w/@&mPI@ĜDHDb BsK{Bm8! B SXP7nbK/蟋;W@a9-$vkᦏHשTotŻ̠0 bx7Fԥ8SvT|B! '3yÐl[ٗfZ~4;љ Mjs" n@A`,dXTRT3*fKaf1cw')sMUP[1&Ŧvϒ¥W^?I&(2jڛL9_<氽_K-dׯxqLhc$X2wq}NF.eہJ{;Tgw~ |%Ja_w'k3zJB`[WӪsܖ)V==oOS){Y`䮫}gnfSxϝܥ@00Rs빋P%2N, ɮVp q) aPl;vBC!yu]ݱg.>xƱo?o7ܽm{Ǩh1M9ub{EK7Xҏ>M3T(V=MCA4?ԕO-,i_ݿzG_ {wg;?v|}Z7?żǷ 1 m3v u dӭEB^zKM#-x0ӏ>Wg^Hͻ;^@~hˣI־Q3]qچuOnQq,5u'Fp@khȦR\8T_vK_ -<ƴM9|fOWsoL=iKO}׎l2 a(@"giͫ\}wM?e?#FHq;{z|m>3h+Db?LYaSz'oe/~gޘ.>|eX0/Q&a @ jd֮)cz75y$Y.h7\Z_tG11k|O/)i)s!B>Y,[&ƚM[dj Dt!<1@Hj[#wy,_uH sLF5i2YfIv,CtXuV^ lY$0WhR{P @&ʒ VF p ]a̶JKN%U2S2$dqP Ű2*J4ãZD5$Y Ra~O*Y sGND +=i6 Hڸ,7Af@MȵoS(|̢%N$RJwB M8 HɱC2{= $q8Mr}$tUB$5+-*~A Hp! wڧ*pNo0 D qEPUd&td6(L*C_1 'Mp1[BUǜ}0ꦮ$ ː ˪J"wGg+- +|\dUN;mkY[Lo %h' a-w/~ڋi|r̿_G >u3:"~k.L0=;{b{Ozٵ| 7ܵK1}q׼<`ctu 7_tZxÊG^]m{>ifhP*&'3Tדwc;چS `gWή7wyK6o1qd^>'w/Ek6xr?=wt]}:"~}c D?;}M0_d+Zdɜ=}e#/.r۾Ol:wp f*Or1e4`?ޡ kIW8c6 GWRwu̖rJ3w}y/۲o|$s96]m7>PnԙO]}Z^kKDOeaB2"¢Jrŝ^6Xa5;'5V"jMUx9d4̲rz6YP09j <ðTl3ެl 楉ЍY"Yhqvv,s;t} u`ߛfy.$Dr"%AÆPGw6>WF>Fjz}i $[~E8FLM呱[42{kg,Ev̄P D:lǦcj'3309s UdZMXP I$@HLXZU[b @FA$7V{~P+kʜyw[}T-˄ 12))*UD۔=g% uT-' wmq&ic=7 )D$BPNYV2#4ׯLTNld՛-gpgйi?`waLqYyjy왷Wg9qqJ:8M_æ3aʘ49L8ט:i ̉7oG_:L];oj繋苳zJk?[wO gu@.uC(/\DzhnEjkC5 U+_=R#묲#vIHd#y7zp&Gs64s q(C= XMØiRӖ? l7!T`d@Y+ܿ^fYA,B1r &?B^)IR0 W a7@M5!\RCDo4^H kvȪ>DR@ P (ƶM$!l% 1m(ǎaQWHLID" L (ÆX ae$8? 6"gAWT=Fgd @ -T}IÂ\hwIM1vlSL.i4`ߗjJFC1 K>؍| d0'u( CG q˕ړWbISؔ5v8c:Կ}Y;]?9AE`HUmʹ FyiV@38H{\%PC|dnnRfpN7zPhYbgLȿ /d6n'G)!L9q͕&{Wx^W2>%qT@>ĕϙIk~BD~0p N#ܼc2|9;:j} K>/=n Uu˹^~֬'(c!tWD\/صfB _5aP H9R P 򄎀%Yl L[W߻B >/K<3 /d+L5B~L 9.526HɃ(I#-(uQNj!U bR[@ B̺D),*cnPdmQb;Rbh'䪷 P"d4slb`^4/zܾVmz@K0"[mɬOa~ (\u ɌIer6N˟25fcu?U'H[%ztz~Or͇LCPN0lPK';j4Ke.<ͮXl.VgO_袛W/KӄO{=MY뒓wŇQbpps:{r>qm-unjxv\JYFF{^%ubѡ㆚ڜP-5IُMwU +VTC&RJT+,"%f\ױ\l`!Ӌ YG=޵}*5'6?et *VeDLyE'0y9Y~x&LA(Bp&Qg.ޘꈢ CU^+!J"}ۥ Nt@31 TeNStX!#d9DQ ixoARUП#jnS Ml1(AP$"Q"JǏ41٫lo ^@o?V U^B1҇qNnGagz'#?Õ^k$ .mQ:^FC@_d4f$FV9"s޷$gٻnb J<_h|0; i}ǡ @,"k3Wƾvזa_/v`_b7ND'Uj?" qLW s>;]xQ.Ҫg V ~WIn㧼)j?~8t X3F3Cs%5cƀY`6PP¨V)Ys_0OjXq?qOq%ˀ瞳L˺2mZs[|ǻ<m&\W7cx81Fh˔)d7ݲjmYjњ FfY.(b`UtalȌ㭻0_B&Yhx'{'5L :xc9)p9iV =R՟Ku6@`(KǑb+2L1v`e" k  >@j&HdX'tBջ:ˮ,x=;)~/܇l_=Ýg^{<,oO*KՋ (qw1C& {rj0nqQ_\  N$eBU!ʦ⎓mR#*bnm#*=jj3&3RD̔( a!#Jibh)[׌ݨ27&o@[ *Q.DvlV3e3n W(ϳ~#R!jj0厶("$ 0RbCxr 뚶+⼫& {2w=bJWj7t4՛ ܲZoHGk[v?f0*q0~:'IOw3|֢@P8ZeLÓ=Khc B]95ugÍm5)7ע3|pUe3d q}2Gn k`*z3cq@8LJ_w^?vIg!'*=u(WCvr.}Ȣ/i]~w٠R2yA/QZ2͒L%AR.왝̐O3;dĖ=wb:S̏a2.hBy"ރjH&\f̜"vM9,;2OxlvtEFg_Y4vIʬs7PiMp(e =Xd"Eƍent  *"%€gԁ:Ӥ! A(/DP(v!0JuP" (H4MP i[ 26 Cbj/يDPU\ yd;^G<ұ:`I ff)%$AHBè#Iq&̖n]p\.h($DJm&(y g 2=sgb ߔ`O&\ [G-ܐ[TCCg&5<@ 6+ 3H)XK;4g;ɻiṫL^dJ6$L 7˄d;zTZ̆Ak u@!;7m8ڴ _96S, Ի8\!JLi% S!Yc]9_dývգAWIJ BADFHU9|B]`0B4v 5>6Afm0yFy\;|hd#X]-Wllq38c TV.^bOgO %Iv,Ad<+?٬u3QdT9L RL@(rdGBzNNձb)#`X/OQ:"Ȣ ,U LX*h E!v5X~Xq~m(42d[*5뜛fU+TbF $LU IDATD)!  x(ӄ@i}@Gb(ĪF9!L<'hRYQ8X+٘n+`<\e`(׿ځf$pڗ0a:Yxe )lzN|>KHZxi C-v, =NlidE@ 3띺=< )! 8P;PR#q TN%#c5;Nn2B4\]#hdgx U <ڲ۬mϙ}Q:qx`CP>!쑽Y =7jjd $䴂J6f_X Ʌl&Ӕ9?hF=".QI`v*'ǩANüKck,΃ٻ2ߋzLawD"O|Nea6n&g=9) tM!~fg `Gi0>1Pa/m4 B %%٢RX@`-;,US+~3`8Ra^3:Gs6j󴵒"S iT"a'LRx.{{X֖`@Danb*pRZPYv)6\TH9*`2`lJV YL5eӂ *"FS(*L*KB8(¥Y 4" 0Џ]o *L^ !j#!1HJJ%"F0*aTL kX+QGxi vCB2E  Ul% Ҍ=N:5R-8eG} N8Bj`y_d'`fٹwhD{4 &fA$PuI|73{Suݺ1-hЎ:l1wjkfAv% {X lPHfd)E"9erMAe9(3< &a~e1uUz4RJA*!@ P()!TNk4^,:,<1|6.xugV_ㄑB@ P9ztg|cgC1UaXUy.?{oC;p(8sֽgs8u )w128޸Ybh 2ezk"<8ŏ^O]o'>R,=U߼eu'5;&{cq휡#XQZQ럩'uI{.1TT+ 6PhѰ)Eߔl$9洟F"1ZiHpΨ*I"A ޫL:*h*SID)h ؄Ə+EQ /Yvk%Z߃lòIZ!%))R ),*2(!a)Lh.s]:a3?ԃ q S4g3 ρ0{y.sEN(6mMިZl31߉ؑE6b1R pGBH!ѕ&A9NY#Z5CմƣQL쳖@g' hzm^e](4X2E>1 LSAA "H_bBfGnF7f>oݜHݻuľBg*ǩ4D!)Ɣ"sɆĈ`ǔ$ XÆyJ5N{W 8B2bJ K"DP(2,ǕP{NsV?ujt 3ٕ<=nh,1&fNXdVN{da|'~-SSyS;m ÕS?КeIʥdR÷=4ݩ :E;y-|ww{]\!CRTs <ܛ?cP!!nnz.zzCU>wKS=lhX2{)]I@=%1(GZCQSwT '".3B|Ԕ?呗v̴}_>Dr8rڑ$=qd.>iӖ gVSq"^3~Rֳ5}ѩgh*U />TMĶ3E:wb Hor gY2{gX =T~c86ۦr3VKNj;+4ܛ4y;{%Xm%OYpW.AQ4 &H[brldmEXͩv( D6lK%%:Xc bC 0dTi]Ti]0 &@`Z*RS:xnc ]RHYߑ}E= H@)# B0*a A#L4O 4u.8=U)$(NSRH1[ݱwެsc| le %ܶ25 -hKTlЌmO =!E!TbN{\ezj$@QC:Oa"D@` g>_؅ j%I@TS"Llʔ aߩ|7hG<Ξ^)aJs(ABF9%)u1-:_b.4hعh18r_arHAE"U6$ '>T V5#2{mk.7KuD5 R=o=.L7qз1k~յ+cY.ZΘΫ^qPܺ~߭9&Mrп{^`Od߼o}LV75fvŒB.^7K5+vϲ[Y%ָyAӿ^ %Sx)^9G⷟'Qiu!K;?>9N^p«7|ze<$ >a#X`Sɧjnp(up+?^.)v@>^3o 5w{[ÕwKFѫVPɣ4zYO{ G`sήq_]A5f- {Qpƛ4xenjαzG^6vkbgnwt^4[|m傶k]{;Ṛ|u|S:cg\q|WH)X׹6?8 0bn }PQȎ2%4c*nٷQQ@YTFڥlZ4 Lҡc\i$!1`+I%kj|`4# 7 jnP=AJl+ p$g#8ܡDCKs7:wDl<"RRRfL QiQ! a"r i0t5Ⱥ ;SZCf) 844 {v3rF,LRmtuSs{8O֖Ύ}!`-Oeh!8 diBA.PZ5|SNFoA`YYP`qb͇O06+%)H=#0>@:YV c0:_s'@N(R-`j jsku 2t/SD> `@쥒3tKyLmTS)Q  ZMuﰯsP?]Ȃi蚻7hV̝%%mv='eW=bd˶vd._{/х>2NʂˬMl@ʇg{͏/&a6:[*$7^{]"QYAMco6FfHkk{_|7w<]x~%s:\WBs+[9;~u? S$` ǿzy1[e;m~%^V|^3E@8! ͗+/wT}rT6y4Ӛ2skꖉ?yC&ޟ.E+wӃ*"3W>yt>rǾq?6zD= d5to\ir{)WVtђ`QUАRsFAD1Q@.'=_4ϞI*D=}^󞕯njo.}30ITDA}'?]r9%AM(UGl]Q3JT+ X>=mmw>O-5jճ3iot3'5i?xw:syoA#gIPI>kUhW^43 5`TS;=ZQF!|,9*[d=(, SoF9~uCB,Mޯ旜afTz Hrlpfl~1J6Ӌ ;@sd c}MJ2%) T TNIjopƳ:jLw`""3HnVy TRD "Y-469:@~0@ %;X- G %A)?]qƆ_}|}Ybq0kn!Tw em_w;Y)+v0:[=RU *I/3GR6]}ULy33sa\rz` ߸ʇsV M^~so^J9#n05g._{* |bc;idGzĉtRّ7i$]-YfM9bWo1{z.HR-iCm'emKRu>ƋhtԨEd{w"uںI5μ#5GjJk7ґ8spmMXOUe=qca2Ͽ9zPkۜK>|"HIJ^KvVwn*^j+f3n^ËwYz΄SֆI缶$%B߬@M{j˺{v?yÆWΛ| xD CܛĽ?]O/\z/^8?^h1{sO-|_|=#m:_>sOXZ߼}챧_[?u*V~箕C=i/$XJkZ 458p7I/{ <+%4¦CLa9zƎ?܎ӎ>|ڦyS_[?a[mܷ7Mvp/];9׮?w‰Dh]飯^|8JO-زpS/ʳYO3ixj;Sϭ8y쟿x+[.t0/~}qRXYYڽؠXv+mPu޳`[m'+m :07}qlOMUrǘ,wFU^;gSF /\Qq^(wO_ޓvjo߾BO(--=u rs|"Gpw:ܚKk4gev䄯b IDAT:`YK7>\ޕNh}Ζ걵m:MI~/Yyx~]~8twjjFDV^y$7bF2 <7|(ћ;)ޛr3s|b/\TLw #!G~qϛ{e&FHA rDy=&[ 4i> qKjYq4eɡe-]~9b@GO7tWɅΞT<;]d{O 81wtҖi#N 꽓Y=7OS4 eW\l0W_Qȉ#Ozj:ҞWGfޝlDDPIe@>2rwx=ߑ|hO%ZKK98%^vq3#ށ?幣u,dzbMkhѓdG*T7i{M?;'Y8PTUǎb !leHv ]+kz0w>erI3P?5 hxg>s=h*_U(qEE4P' 4:*6Ӆ%鉅FeP=t\" s ɑGf0#V?4bN!ڑg ې̬|1 %rq6euiXBE]4m)jbCBz  f|EdH#$UR&^ĢOP>)7T]? r}#e}4ןY:\>fܻ<~f ~y+͋eGV6"Q}c7w74,ޟ^Q^qMĮ^y~e[=z X8#'n*o|&G4U1G+%U=O~5>z{ŀ'zU^_7zcD;1}7~ޓxiIy+s …S+=xzyNԷn)=T]kSoF}gbB^acU7 (K]|۸󷜿kyy+6?zR _u8X6m=2 GWˋMC0Ġ>qssg K1zG.rjؚ,\^\?/43ԑcNg_v0xk z׿~گ||Gj -ku;u%ӏ&ol2dmO&6h@em>2l[,+k-6. p1z'9w$DLLwxTrJځe۪ K!d[(Yw큉қ[z||׼+^Yw閲uWضzߔe+뵁Rs)#O#c<v&q_01bow76w) LVwS_}W${o֟n-SZg:_*o_ۺybcр03(Dܛ8ドp2QYǼňeK(<cl*i-8Xm- ;kZ SMk\`%@\9y>䥼 K1Ja @ՠnxsQ~xy"q{~P+t.|Ν'F|/N^&p]{ǖŷU>`]*p' "WE,sݩDQ!`[l(9?^Y]_Ӿe4[ѓ8< b1K89Z+'*J kWڼDv ,Z}hVyJNnR:h/>Pvcp!$AY+1`iB{s⶯. )˼e7I*T1(H@J |*ނI9# M: Ɍ_yadPzةKچdSDv𺳶5o۪ͩGŽl6p D_ѧ,8k]F,Ht?p=Z7׿V=Wnm5qXkh]=|dekq^JX p<=yW'my|&e >}馦μ{G9'ו7Ʌ2=6k+{N$?k?Z^Z:'/L`RUcuӀA' e88:ڏp""-J Kថ@RUY(qE;)ȉ)"2t@4i2ArPkNBC  XiQв]??!71F=(?]L[U=Y?pG}Y d}\{^DFD,D^f{2%pvMkQt}K%ݧCt^` DAp8/tq9uwԕn){ϭ5ahCa~=#.qY}a W9bhʳ}xrAN Ƿ][+q7z!EC>ǟFdNgo,/Me8'\W%ы1>fPڲ| @^VBHLIJ%]Ύ^)9|Ԡ]myp8Lec\L;ͧypFh*Nse^wKϳyg_q=n`פa 2ޤ m6nM{w>DCy<1#jv2N0=_`9ktys֌G?u w&t:d #{NVFU4L:Ι siq|xw:!2}|8ؕpx-swU/=냽!,=.F* ZNC\p3yum%FҤ:BN('B3 0 NR{8'LA>D ڛȞpbN4TTF6prq E0AͦB ڊYEH% ?,Xy{O>}Z[H/HuI抈ll .8&\/s\3\ Ql,+Nzck8Ez @ps @]Gq*o+򜠼tk "n8<,Hs;7.-wLÂVC{tt,;vTG9KLFݸ[USQga55/F .0i-xmE P:dCK!j(SEJ4&6 _ G ݉V!>ꧬs?`}@! K R!j}2ZD}Wn.m^"&_ư-r+Pq1dqX@Y i5%FGh#}ҡ/h%CCLcAIs̀%8i, Rl5$ !-oc g/XM-2>{^`wח|OmwԠKg^c}Wl^o馢M"@.H*#DP 3$|#-?t75"oo3hDܑb븫ںIV89x}1\4o>怂[>2v^lR$5Ճ_9K;ah|ṇues{/f[ ; l+vN?lo 84Tu#b \kkQ6l'4舓!Rr: ~ϋ+yL^,stIםE!?t;8U֝wO2 u/tswaoi6cD#CGlEoCTnC5K0'.0(.l:E!l;dYa"`@ˆL̎K3%EZt>( */ea*FaB߹bƾ^[;yy㇨7%Ɓ6I8}Q" cp9nqc2:B?CtK !s܎ /"ϸ{f>{gbњ +?slݩ ybh~^料?S+oY{_fg*:+ )h6NkE\-Mv!$?#seL9PJb'á10C ou^Og hrrBl? gX idNB#20C5$#ԩknk$89dN'@5k$5rP lWˁhӧ #@Bغ2's2`XcRrn0:**P# 5bx$`N-˚äm( p\I3 /Uz:YV"pImENƲ^dSɡSePZ80PgE'8I[zւ'#_A"1'k:ZЛ&_w`Ф ߩo+55=Uٜ wU;Þr/$9`UG}w}sƟ>wEfd֕Q='"xa̷7NUMn09WBvYGns;plٖ7cfƀuD;6ޝ΋f}Ε݉76Ll°⮗?~:HPr]&b~J&[&vgѓ*kJ7j(x)_tSCCgxRmk(乁pDNĈ#~,T]ka]븍=u;ޔ7>cot&?fpɦt[^ѓ:0j֨ӏ޳T ]e?΂iV_VzgL9嫖cڅhOҼ2>4W kgmy6TՖ$?`jK{R1RoBfdPIZj|.:;^9<7q\A`؃A`e:BBLuΦek})ʵmLٸ9~˦qp]pSj`˲mST6}M[^H}Sͥx#Ƴ:31-rh[2e䨪'O{P $^j6% 4-QIAeBT ffC)`:P}Smj^Ip@)XB߱uQŇ5&V>O0 *t%Ȩ mnP8 =Ac&Z\˱,""9n sncMZӞ1]-Pʯw}ElGVX|DCa"YGl]f*)Wai!fR/$L]sg9@.c6-Jz,`'T+7ҍZqBtgک]5U3B6Ҝ'U;*.H=Ճx㼯޼f 'ы pq&WfOoӝv6>b;sGw醉هgK>f4̘5f 1O]6S-wz{:co?}Ү륑loN6j}s?S}UC>935VfbK ͜OD̿-+ٺւe&~LѫMkNjV +K8밃"|zӚS%˷?׾_/9?\^P9sRږW|fٜD,o]6p^<3Gܵo>TSǾ Afmxy>ީߛ#:zA c/3Ovh纡L?|?xi ''+Ֆ+j+oh:|HCrA,/\rv%WX(PgK@qmiTN$@GOV^ 3AL#! =05uuyȊRyH2u]Ȅu˦߯n ˉMn;{K6OA <7W{dseo}/Ϭ>3jL$_ՉjfV"L8xEՌA&MGl2MS6n+ΟPŗ?lޗF/ k$$WAqbBW?ߗc@ u4G"~w3l*$+mۆ*>ɚmvG {q50G|O߹pݠ9זBy5ai'{x'"l#&H"jH5Ė@/ݴyoynucwAN&` ~v/#Z*s.LtLmXZHI/9^7. 8"0X&Pd=Wƕ7?pOޛ Vh.+J~~gIC5]]n29\pYy@y @s/g%S[@XH3gm (fVl4-t^(.ܤ-ӹHsMmYTr{* _SYd$LB7 2[]ʣ*1(xЕUrjHAO զ"87M K%TcQTɢq\db*b4 `ruKWr*е-:dCqT܁X}zqƦuה!Cjd{ ? zڀv#Z#4һB,- ۥ9v_w _Y_Yu9#;߼>plI˷:Z:!"pb[;z{nA""B{8Y}oǬ'G(B"$:fpM}{ k/{Jc;Xqj&;=P{*d$"N)uV>RWiuz,% cumJzsM{w'[& `te_z_5=1sgj.2)~Y_ ;\GW!3Sfx/ ||8.9A@82R"{%1V\d8.0 @0m#f[rȢ'X:'{uU3KW@ D'KA(k35zӣÍ2R?ED5id} xZS/s/-W6@Qխ t)S8 ;g⪙O/Vn\]VY^lXlh!` MZ{ "8r/67R&ᛑpι"MuG?$۽pPFL d3?.H`tbYj.3@| #K ϙv /1,hU~+ -A< FƽofɍGp$[eeD U"e-GY,S@ot!gLׂo!fhxD,/W~ٶ nI`.il e Li\" lD$[8 b.sc}њ߿3l"A%A[G7To\&tT!2D! s#!^]_N542*&D Zf_m1@i_҆ R*V^rPE@܅44gԸR2t6-Cbo4lM~C<>*oCy\՟7E%jd!/6خNyucz q уU&|N)yT lƒ.F23,gUi߀a^P]f`3E:@HPmy@ٷ[ZU ~Ky WL4ёrwF q2XGh%Ky;*٤|I+.G bFF&X[Py?l,I>OIa5gB[Ff̲UfA UP!satiP*Ԃw@%RQ5SgOVɵ#,H@V+!a@kK'5p#&Cf[Ptl 0c2/9;糎 aɰa8[MF@ `: M!2#Dl  ?\܊+O labv̕9/0xx)")dTH&xH"i;Izdz98c)'QrM1R[L8!?Z,=ՐO F0==(&]L,JH ]Sy͟-ch%E5f: H6$F8Qj6gC $ժiYw]@tGtYР, kVgk6 (W T4VX״&uBRje*P M`Py"""v\")0o$%C$e4^^v2Dplx o ~] (^pB!@(`PD-a?+ZGwsK3 kz_$Qijr_j^cZ,i 1LbgxȬYjA;QZ vot_%4( E)bsrIn z4Wߎʨ:CKUCH![W[=\)gDS"N&Y^qPAP{b*B=ݒIo {c= 2ccV|DYjl  ;D 65PP3eTyCܻLNsoZBe 1T@(>B5wfSū s YkNJjzzbwÊ+GZR06d@ Ēp:{.Hx 2]HƳE9s9\$佞O:,( c"]uUI  ~%8@DDi @ ?l3f\#\J4b!j-g2ڑ#ֶkVi*]b:P>q*J@6^J!v~<#U5핒cMn~#NNŘC>˔T}ψX(DT!|z^ >Pc-ӤsS[ x%ΣmL7@6lBOݕm ˿5˵`k ?ɐLZ6?/bGUsGn󘓗`iԤL"C(N"CBgLum/[H{I:j\T{+n ^kc ҨJWcS6~>~q1c6D->6%"CtsQ:/e̺=V 5 l'B3T !p#;ZO0L6Fxr;D 8 Cdp%.[&vE-{؞\[}9 b;R#`qx@> ksj-WRkHҘ~C3iQ_-A!bqNi X(WMƘ5c,ҏf E,\K~QpZ7~@J7?NDN Н %KF]?f_JH:2r$lkKf+1Fv߾ MY\{/{GlWvdbK!IU-,J$^ )\JMB @)ش6>!BMTYR 4M!K˝n%N5@0^#>ɾW"eQ `O=@ [nZZW 151w@DB7#x=(V^"EUͮ,C=N\\%5LJ1eE$TAcN DlkiHZi@i#9H q\Omyd9f?#OSF ,tX"9Ed' VOIՙ;.`r82Ph<@pЮ"}k4ń텵ʦ^:}JY NT,MbiToBi;[С [!iYRQ+2O:mlAiD~kHC\2luN3c/>A?2YDWx&!9^,}Q ޒҋfcaBgZ)֢+ ˓(I ;M!DQiF,}jWUq)2`Nlܚ¿J$ãXcmР88 H0n)DbWHNQ<[cLM)&ʨmֵ+WG JgE( \0)`w36BGe8'5@*cʔ 3FPWq8s\Ƙ@i7xzu4tM:UI3rX)+ A aOb)`CP:wY˲?F 3] L0`b=h[<5=WyD.!d}wU9woOB'JP,E W\ۺv׊ R J  $$@z{3s{Ͻ{a5̝;瞹2T`"sD!8~d$?`y;rix?~KyMnqFb}dсvAb6HLz_U(%Rf %bV#:9-(yn!BHYK $*5xϪW8ersRXǑ !F[o9yx6\28I[ &_Ȼ3t$\E9MwNj?o“# L.=yM!>;+"ď=4eTu0E(jJilvV9 ,|gCi+lNlOcD@c)sOӄCqg_cM &s.أ3 j eK`7筌C#OD'K8>LL{j6~YFE$-Dt2 LlӫQ "J#jlL&c!Hg(̛o.Ce+0(͐ Hf)PbM7" _n ׈$KDj+Jc@B zڡ[VK Ms*M5-ζ?FQUQTJ!)*&Yz!5|jqW(`E@enʪHA@YX#-3h v l~NE+O UkDc#jlY!%\&rD!RT4 -yZk&Ӗϐ >oʐ/62s] ;o?ʙxhDmlpW 蒿%y1"q`y # (D Ť4 >ڬ:Qhv *M ?Gȿ[#ӄg4PTDP!*hJNeMC E C,^{2x=4A 7W=!aWCIOf8`M>e3*+Ov6AlRUr&*8(+ndG^yD8uo̟1idR>߿s"nlg h;Û⎮OW7Np%rLrR>QO䠒{F¿BO{7ߟp5 ]h};e3n̲SXq(""zɥ΁":o<` ̪vrOoB#Z!nig"sEf񜍋l7gAaz ٥@@hZ'{*0HQV " ,C9B& *HN%}a[jyS) Ш5:J(,@FHY.et0h-6ﳛ E*RXH),*ŔŰW5V`@GY˚@nH6"[lVJ&כ'D`tJbt!2+˯`p7p7/*p4ٷ2ڿܔ 5| 4q<JeT 3mi-bUBĦ@%ES4`Bxq1CF; \9j.^"K܄LjӺ j#%Ñ:r$N 8t#(&K7H]!XA" ZJ3wղ{ēBŨlֆ PEHZŴL3w>u+{þᄁ`̶hP>4sKN{E ,XIІv85檧/xgI*85fQ@Š4UkY}C$rAF^4V3ٯB$q <5 {0@!)"R@YkhNz* aJ1!jBU"]`N#9:Tf#)#P1";0>J,`r\ ifK%l逈QUH)Q!(IUi'r"B^)Q[B= MZFDISnxu4DH|+]FrV/g. Zw,vܹSkΌPN1]D'fQe%U!R!L2 j{^ǧ̜BD#DuA(*;c5wRvmT1! N%B #OK9pH8j ]k+/_?rA19Wkr1XyŇt_"%U"O_}RƋ^__PIC?|,>~g7{p%8{5 \rkVuk{e+#ѽ WS879NJ$w].3ӔqGZ+_7ywJ _o,_xqS_rD?yJ_=]qLj<}Cy!ϪU(ho~v'!GSGyɬ\zۥ-՜!*n=~G$"P) C߽h1Ċj%7YL=2^'?um7-}p˞ѷ?s-R$)Q!N,{k㫏bfeYPŠ*4pO<4K Inj)u ')z6Bܰ&#y[9*A{ "R|KB7qS$ {S b1BD"5j Ĥxv/gsJd*%08HۏDY< j@J"H).Q 1B(ҴhSQSc4,"Be>ZޕXZ$/.YT\J::3J$l4*e;8Uakju>Pד,^!.= QßU,(U(({]ǔ4L7%@6|ƆQhX*^"Inb.Y3 2/r䲮+XFəfuڇEycw;;sogqXlrAh9DZkc+D 録Gs! vd&BwɚkC fTdA4mvv29u( G໗u'`ȇu{}ޡbWoKD+)b^ދgw:fqG~w.$UN?˧&`(0sџg,Z5unDh(?.C6O,X1O#;7F<°HKW_2\N^>RTT,U.l}CvDgׇ\/00$waZ*28HHwFB2ErpYQu Mjh_k7maHi+pCp7-ʼnЋbNP!z°B; #K)2S7(J dHD @؏Q P(Pq0"!FK:KrC7{&:M I @RJ2PJd(p^\M4- RPEhXP+])s8o{#FC RvIR01s.[2f.@оWU^e #`J=!8cE{,O;$ sӸ'ތc7g_ VVG0Z)7/23.DD)V[%VlTvH_ ~ Ū?;v$ۼ)vTbպA<3čXs-RDR۸-xSrl?8!MGpiJ)DPJDQ3[LZahr&N#OACn]~)N!HE! (P%Mҩ^bq,OœT'FN&OaKhr5:zϡq㎑Z~qם&t6F>A_[:g җSgrJa;i P'4T~}Su MW?vՏi>|M0'O_y)k&v3ԑ$n,%k6=`\3#+'u5z`aǨ"+BĆRrқyM- Cwev Ÿ\OzLku7r==q\=amkd~8}|ް/QӶm١+7LPv|tRgጛo[|= :L}r\ kx~={wnX(u9-{~|?QJ_^ M$;SsC8󷜿}oK9Ǽyܗtu uu{q~D'k~7hP83x~fN޽7 ^~{S>^GY.3Pa~{N:-;,Rǎ{cѪdz*ܵ,#5x`מ؃4ht(O8g޶ڣJr K#^:kcںw {lՑ _=Db[޷nFt o>E=43u g/s_\H2PgTMFM\Y6iB0=D-=ϞP~?5e#?~Ycxz\zײѓvGMvo.,)9kX>cg؉=%75R,Af0< |EMb bs&حqRI" P 2m+q#&0E@RpAQFi83F =Bpm>N0qY]i@V&mv5AD'ilBfa;+C۰ę.lU:@JETtq%T;bA Y'LF/Dyjj*GdWmO*$uJQ6 J C׆"(j}C4dͰh3o4@7]{|5V䴒;w?g`&R[ǬEO#|9-?C6k{//t;G1i-_[} :z{\{β ѽg8i۾}SFVYq2/,9w<}['Ϝoj܇@!w۞G?:ŇKudR 4SdVDJpN3V.V]cw rت= *E*~kbrY~ؚo+Pd#.2u Exqkn<_=r>yd.}\H~pGlE>[(YsQ/*hF*i7խ70<(L #4*V| iSz1Ko,fB,OQI; X' )<7pZHNA,]l OP`m+VzPlq -m,U;Gi 6pv$3uj'X1ؾ7˪Vf!P(ٳx#pRwVHDn> :=\ wȿ>֝>H!4wC6O ek6iu9à G6tC=r6K5gD[D t3g#f{8C*>(sA*`w4uR8.\,3 NcT"3ݸ| 8CdRGq;o霙V TWy{Gr̰{c/4aT'N]}3`/^}&ڲ ^7-{1ymxC {eF]-ϭrƑo75TwuZ ;;[3}TB%Tk;вCo#{7ikmsK*>j3]vʪCO2u2ꉕ W~e#2<ۿ׆b{$Y{b vܲ{oYJWSMUSK>f <$,=|InR\qŠRZCj,W3+qUU躏8g/wwơNY=<lݣpދw<~m-?Ƌ8w˞a9oZ찁)޽!? g^;ǎUX) o02+jysZ ome,n̰y{l+3}ɯ>ݽm >9Ǒ}:d݂W,Y.ym]g~Wj7MzCV}-+ߙvJPjS-_wzDEssIf˔5$_=fZu6QR{o_CjWB;;e{H7ZC1FTfڀJ6 ]U_=ɑ`gWO_zwPC;2yLga+DEI&vr*J#UCS3@ɼ,Z5'!HP܇-C틅Havc"LCO E4[s0;g;n׭p˔R50tq[ՅƩuX-;o;GNK2 Rhv󄉝T FzK鮢&ҔU+Mv@C ʩ:"A*hcg">ĿE(4C F!F 2U4h䗕P H"2e> S{R@iF NR4P-5UwoOӢ#oO3|~́HUS^̕io#2ͣ4\L k)R- Rye-*IlZHieZ9&ܸc?'TOfϘºLS _xzմw=E ̧^{wU?(R*0aȞӳw/<* n/;:ʟ|Ss8`L=ww7dID1͚X0}(2gѰjaR%̕߾uǘ^GM.<6zZhml f{G̘2j>JxCU'L#|}Xbŷ=v/~࢓͋ҹKV3qdऑ_8ggd4 P ա=P4jm>Bu q{9ѹ^C־BƖ1Nk7--{z d{KqήW,$#[z`gw[HD$RJ=m8t\ xiޮc4i&[;FiwAUJAaI#0wg\!Rlkly>D-UdĖ!T3g^0/D 贠И}۹Wj-یH-ڞHO'+O4$^l"ݿa x9@EY J!"BP#=TJ),BDBKJ7A +?Ͷ6%2& p箌ޥey'E(U4)]Il "cCKH+/?'O&jr.)_@%3BM&Լ nF_u"E 0sspͻ ihj V@X#w2a,2~+D5°l\/iYs s}zz 9ٯKlMDXT@dж D'|FÉ8|W`{]ՙ;tQiC=LeUf .&s NGrDԐr>-ZYM\98KDV?S3{ss.9]]wfSuvĆg^r+qZƅ/" ֞y8u:En#E j>3X-l>o ":ULR!ý^D$4S^>7̓{oћv /?pxE\qꎗߚ?TPߺo]7ކT/:8}|Gy̳kdLE*"}щkoy(9hmMpϳG|s0'PHsSj4Ӄ'niB܃8e\i5S| GM5&=*E5TL1VV}pկr `uvcHc "Dմ ZԐ#֬]lфХ}9'ݟ˽9I!pZFJyOfokHPFZM*Hu($XW{xrz7km!KwᏆbݲg[GvlesΒM^pC>wK7vΦۮ?dc jRD@:w/}}3SM#S,jۑdQ{wSHĽhݤKX: ~Vi¢y=oo={'Vt osflxV5S@qj?0TDpُ4.qFw-\>Ck$ o]ki܅/8>Olv&@#[{ 5,|gX? .zȴ{([y*>mr`eji4GBʝ ggQfRQ)b(J)KCʝIDn;O΂uc| j;r`[֨"[kԉ>Q3/]1-ܣn{}'n;Ϯ=<@~"dD":f.ߞ9lH\-wxઐXMޞyc)=Rn3ObZb6jZ 8wsЛ+>hW\{ĭG׎OWϼvhϐ;bOkS_!5%Wo KX{ Z)c>H@YizH)J(K^ &i@6)S۵p u_GxX+dcHUH""Pݩ`!U<}/,:x& YοcVXr^ղP %ןlwWӒu\2<k/}]?3;#B^56-{n[xצpei{co~p΍>n%G9.^?E~p$Yt#'ޱÓGg8gܑ̘i`̟?pRzGGL䮙D++ ?7/})3gwW=`l)X}/}ꦋ7eMe3ov/ѕON=įnk4ZTDcKni}5}ܣׯ4&ke{o^0 _y̒a] 3s 6>0(^ e3k #;4 @3V7l~CnY8*@úʟ c q *_}! r_>{}mkλKq~m{~Wnǎ*~g'r#ܱ-y VPE~wo;s'?ضGV+jR;C2ٯ.Pȉ:+"W$x\MФ]\vJR3:m/>uRz汳G %wNa"_ɮa߾M{G?Ϟ/3j[œ!54\0gOZHG\Xi G. xk}tB.QmN/JYƃgST RXNهm>n7ot>NՂlQF.R1  I$N=M?7;wxcOsQVn g˞oYxOrQpxrkSyu-; 4wmRpùKsٞ\5 <ݺmw/Z#ZGq]}߹#טk'-^s~^szKϟqΐ|m3"xFՐRK:ϝT\_o2&`qt$r.⭂|"F{Lu@f|Ar˼?(&X"%PHwrD>JgqQ QZWSP_E y <|c0~ Z/c07@U15`S%nJ\zJKnR9S--@XmDHl0z o#.JNa䶝RvCa@)l<']\uoB 6woZcFWelWrAҫ>9ϸCFG2\0pɼ}pV$mp?'Y`mK'|ays7aOI^eװ as8K^<00TO2nVj[9ކůM{jkSOneJ{&ꉣ̉4a@y Ev^_J 5 Vmػt~<6`t|sx!)9S ͸CD,Є-MT;SWvO~j rH2fِ_avˋ' ,J(%܀x P퍛02/Osݰ)k*'S%]JhGQ;gb<*$Vb>d: Pc nCv`K0!~>G՗ {G \~Gv 8ѭq\K邗?:fqpFnl !]&ҤR  QeʴE2H9D|V;>6 @)bb3Qt3#I!^Ⱦ!yMͭ|vXEf+ Y~- F$&ϖ$ ,u;B5MEL?>=â黰r\b) ̙B~Bwk3`ŇXpmȋ۟.jQ[Jթrw/EGz%EPR&98V[Y{~ Qy4%g#8P偅Jkp`AvQ7&^w,ۂ~(EYn/c Ŭ_#hʆ@gT͠'!h \J w<9jaH< {g ո3QF?7VZX'†BW \|t"̤qjYQ$?ZܮSN>B56`SLh'SVEFO\xeNNI%BC7+A>mv{of *j)a{-y#dy7^DrA hRUF*'۔\+aT "s({L 5p:k2C޾G;n\Q7@M})vAR>+do.>ek[NՆe!*e?QEDt1]x_态HjCjC##C%5,o-*c<.ygג?/r> ϬC&y>K(\hM3J\Xw B!K}A(H`{1x_?` [x^~+lR7 Ug9}i"1CG0h%f3GPeMoA}<>#Rx;s7&䋴/KAp^x+ >G($n:8DP. 򬡙|+~'2v7 Cw`|_3af|iYsn཈dP#\$K č@ZE +4S! `AgYpEirOr[ "P:زËS'NKUUL#@brͼ1x|ueN:ϰIPaEaOi _4L1e6;79lM@ܥMؤW'.q;f Md!.*--@[ʠ. Gv򡬐Q*'X+V(wNM/hѸnr m X.TZˈUM!}vȤ;g(n}29-1w}5/ Jn0îM1S ' … - †=˰M> HF))/+;t$"Hr{߃ 2`cE3?ɂ@J6 *;g% 0yyAWa}*:A[$yyӖG"9i7moح0k[ܑq^'#6CyBJ $X?v$qg;CO+#azH;t?C4) zB %{=&7Z%x갨kS9c(M Ip6 4jb Fsa7;楅:ixfx#ռY ,\rߪ2<=K pnK  i` MHn TJ8'7Gۍc~`gT4QAL2Nʐ`?2CT/f3Gҹy-zѣbfWv!A*4ax3.H)3e lYW!YO ! G?j9u 1U+ w?ANyY/Gv$&?1A<%PE_DUv>˘Y/C! J!>0_emcHB~‚kK'@,i6Iѕ@:e`5g|pG,dYtHvh)Swf^,gQQ/ \$?Lc@(<@^]*Yvx?M.%H02 #ڟbO|Ԁ9`VqC6 k"XPAHõZ(\,ˈ"RJUjptY$Ujf`Lg!LS,Y7jV#NCD Ś 4P#B,*hgmfLXZ>[$ $ |[D;Oɵun R Vz%vVAtMI fxi0!;X_%䦶R@LuI ).YFXaf6P00\9 繻 \ ?<2KXCSMVFJm6@3 "eda_7|ucAƸDvDfX%B~jJŠoΘ6 ]Z3Ε~0f8-gqRExċ5K j @` Ylfr.3I&֋F/>^sfHYLC1)BEbRl0}ưn+)1K}JT :UD\~ǀok >zTkI52VȂ<71mw\ÉG!j"ť N ͛jE%'L?NI[KK Vϗ9Wěde)%nУ1AX[Lb۱!(_ALSs##4BS w6n nb`.r$A;GaƘ} [z|q!h-QM8Tj?# B 7wy| Byf~(c.Zyg%u/Gm>MuP)DDUT3%蒠w>w^m;41F"$")`6r6j(2G cVxLEe^Ok ,J^5==qHSpn}Xr.s[c9P_,MVh>6 c=Qm 4 `rcI 8*;5mj濫ƊRU H%xlJ82/8+]TU\-w!R/<5 벮稞NQ e;EEg$>=9d;N⬫ NfV!%BΦ ]yj1ª]€etK E -3xC2B|cqsW)Nj[Z8k~D.A,KpJy#[.cbu lpVq^" tYXYvB_{ "2k4 DI ԖPz0b!lM8䳻E!>D(q1]`K/yXb2@XtȤ9%̖!ȺlPBmZ d S&M=NG_-};I]6i\3aORB)R v!%U7 5-a"U"דU1ZV31v R} zMJa3DɌ`=FO\P!)Z-!}<DHL))SZ:8z36aQW0^I`?Y}ȍD`,T0 ǜ5 e Ė$κop' ʈ97LZ -3|bi:0,dU Z`3FPC߭6G2K(}9{SG+Iii;uw@{pC]IB#?,GnʈM#? ;wWҤ=<iT9*J֝R[JF$"w׫qAשKP 1;kvD5`չ2P &\ũ?hH %4qUFPNFYŎlFf! '[j %{;ͿCNX`dUa!Y';0r%(`LÄOd]:dց*?͓T?Xf *X8v"1E*dKݗ_>@fqA V|!ՆS}0eJP5b24Ht\UyŵZ2c[O#k~6W0G/>#g7|vkwizg 쇗X?ّ/|3 IDATO5{owT}\;JI+c{S.D!CyjSwˆڤ7 ] 0\ƤD[8S%x[D; @807_)ԒMI Xz~ǞIV!L# ?t Jgʵ$%. iY #эSB5V`ԟRܫ|q@r EMh dݱ)~HvԴ1 HVC! ZP-o)J[hP7ԏ@ci$$sro $:X-':_}Y++%堥`tdȆ0XN TW#O &(l QACW#ݦ9ID`I PjaL$FR3] ;Jl ZYRp͈R.}D(9:1蜫nBRΊvDS  mB̺sYI V8 5\ D詄ITQBk/:m#"b$9FjUBVX=/Do'E6~`vE#aLi 6 L 1dS%˚ё8I̞ Dȷ xJg*|U8+6UfZ8RqpPh'\0R@HJʌݏ0@9+8r>"MgK3`=\Br? ?s8M@}rIB@x{wBǷe' 48+A2i➣c`p/>Z={'~_{oc-YMA+D|oeh(Vn=1ok] ~%˜=m̼-8/p:ӫa0MHLk~1;n_|O#^Y.Q[QS$b[{O0|A{&ҝC2r'.=o-O!Ā{}7;9gNӒ`H \P s  `bB@RKHJJQS;T}2$0ϑ]ˊ7wIƂ$mhHDy׎0dCHl{0o(!{9ЅG`xoe F(B+k V@[mOwɸDms(U &.\'@W=J % 0[LhMxǯoMUDꐀvI& 3D-!b4d'@-bc!DoѢdԾ`D.mHx0!|0KyA5/+o uPU!L VsdX*D> m$@j ğ&Ӏ \ o]Wd]A@")&6G-Atԇxs#w-XyAwΘi-M _n(>PX jGaX( ]>㎅!hCKaQe-\ȌZ"G^}ދŏ8_~qi0sB-|ﮟw.|n,ۥ6YG iCgw9[;hݖ,?kܗ 0(D/7.:ٹr= 4Oha䫷fw)K5H7>Tc?w'0sꞏut?d})+i1pqo\{A뷏GuU~YӠ:eo! p~Ӯ1} |% ,>ЦuK/w"v 78- ]]pW:㉙p;osǸx!m|7\|۟9cٺ\{Q|(.Ἱu2VUR7gQ+#*{ &9LrDՏ m2ԟ =CĈe>giAL W2"q\qurI*(jxw;G'@6TlXl7:( 1""VG>"9z&eW?D-!b]vc pN [ڡDH([Gcr`7½ kmN+}ɗK )a9Sqxϯ׹i+ApX<S=} R]^8ŻYeY^#wHNg/tCC^i=QޱϨ+7;ᥤ+?HkzIF:ס~2ɯ:6LO9nU|F'ܶAD$GBT.zbHRHF6F[M9Lo)X 6$sj9$`K|xC0}žh{Od־c{?|?}ޯ|#˧;Ku$%Wҫ@=/ɲPknKK?Ğ >z[ެ|ko={:U *FrK sO^3i># s^|18x^Xjڊ7OY=8<<1b{g/Km"B!Ips9zvOY=xiʕDͮ&gj&ƍT}O[ K$uSf)@pҡoG/;{IhOFYZ5(GWÒc &ᐧ5R6!;oÛhL?S'_/ý`[F_Am$7X?8R) ~Hpn"Z).]{ȞKOCSH4zVW>Uekx$0˳^=G>ḑe(J) &]Q\ waϗH9tzjΒ?O [ 2 & L} EL!]Voh=!." !WU~; H?;d݊j.*imURB "ILiRK1.-FZ`ư/4DDBжqPRGZ*F ~@TIzzo~%{)}Ƥ4sjG@= W'}{GO_|sX9X_ՏL_]0L]/G~x#o8}7 叟CgtSs37w<=(ꇭ>pvZCqpˣtmM}Inɧ//nk%K%-_7 |ʅߺr#rp$/:9s5TDebSK;rڎE=|W.{WxŃt鳿ޜZxQ+\uy/nhUdW5F*FVG~w$ ]xksGܚ]o''>_]׋)7AOڽ ^|s kH{kS' O;|/]޾oI_1>oppܧhi.wu#IfOً7sKcagO=3X(:}Ք:[X4/ )%; V0ʅ._yQ/7{ֽzYy+oͽO5uïl>ٹNN[Ͼqy>q!1780\WNC (~,Ɓ{_T?b ~7'wm<#~66v5={;y\`Fap91yGz&uW onrcn3zϮ⓯GnQj.xκ.Y\A4!HG- X_AQ b, Q Ced_!  /P((G%b9B!(b %lcsErn Ɏ;A #wH&ۿhQ͊AT䞓#_9T)[o c%76y`(@"00J5e)ʼa}ҌeAɒs`-UPjAH %Yi"A@Sk+hDo=c5"">AY${ Q#sS!}O^jC6Wwƿv `Ụ0EϠQe!@ͮ@)tK2S%*rlUka Fh IrTJ5 [pO8L3\$ތ6OOl:DeE & lze%Skc*]c 9k _{{ۻ(6*},8xjn|/;鉕O<^WwijKz O:|=Mqo^ɝKw6?ϿJCy?esOy\n3'[z)O|z%S|gS., Oo=Oo|`~~ g[r( -PGb{P)?R6#W771զqÎ7s-u6=sή?;cr熝_/u¬Nu^8_v߾򉻿q 3ݻy[u4-u.0\*-ͯPƇ>3zV{+7]'?j~c<ͭ^}{ǭ]ƾij#6n}Z_Nci"2yiw[[Ӷ?rK" =>'?jq=c|{w @3sG?zYnO=gN6f.U:s|׶L̯/k9ucEKw)GW<40k_jBq0I>|-O֩NzY4%-c1O_JfJPI% a e ,vt R&lK6{ᒠ{{ڡ]|ܲԚz$ɯ~{4}Ҏ9/ ;qBH!Sԧ^| fs]}ꏜ]ϞºZ~-Okmj{pX }rl\BJ080@jD7_CPB+8lJts UZ&F b])/c=\1WD*#<l.3C\d4Oj)R+ r٢eu)DT,BCP ^/r-G!1 oI&udY.׿ kᛓ"A100jo;>6g V kb`ڛ0gbe^Px߅5& 8.a<ĠnDZj32e1ȬJdwnlN]-[;Zm!krd鉇n۸s U@$o脵|؇_<zqƔq=9s %hD'fi}[:Z'Nډ6zE2u7?|'?6=MϬ>j 5)G*rS5F pSt48k% \9}>caw|vu7m$7}tAWչ/eF9 72QNG^n_}-m]p<\ stj Xq&\q++O7XSߘVpՆ)ϯzHjHR팈Lb܉6]m9ZG>|;:fѮ[: >wCۻZ/=+=3360\8]/S^~0w1 WO~tCk6O9O^~g#xjnps7?|<}{_1]cJ1M_651pqkJ=m8q^~0<)w.F*T) N$@}Z3_?d\Ks?zXm7gt 4X3׍78b~%fCxxMU/՛^:%!v7!`P]jM@Ӟf]5|A+6L1i;d07`]=my8GmcyGxtQ8 ;Z-=w?e'v*C$FֻØ Hds` BDe )TJ%! 0"CZ %)=8*Ȧl/[|C$qsxQI]S,cLDRk{hơ- GN!"קQ7wIA Ò9ṃB[7WfDqO;ob"!x6R]xJvYp87(ss; dQ QC@ᮤQ T_ K_0fQ{URmuh\”OȒPkB2Su;e"$.z)u@l#Tl}E5FF.܌zcE d"Mpҁ{I AId9s gi3k k498Ȓ~JTȖm %Az' Wk!JS͵>ibԦ+dS* 1=hr֖н>5́Z \3"Š5c[?^t-Rqd{guSn}^'s~4U:oYm!dP+־bq,n| By˜zRDwv5t|֎V N=^~ҷo={ {oZ*{0:\Nwhw̐h}Gr'fS=}m=;+hNRSA{I#K`$R~h$d-Ug{ǭgy;=uhؽ}O{TXmw<όsqZs0?,gɇ=8\Xc{A=e ڦ L@bnz{~)| xɳ_6LާuX:2 rwZCC>sα{U$|-YyBPֿŵH (7r卻&>2 IDAT:l5/7mJmTclbxt!Z~T+Q`''(\2K@i'S @N\r7ښ+/Y;+N!-!yʃ/ο`^:viMip|k'/~IK] ڡr8pa2&<$ *]S $ 8c)  XbphP(QI6-L-w(J< RBO:s9cRDG4ֹ@RGNs`_7bXf /k7$ qK[|Z6vvcu!~#2^f*iCYM 3?E0 NX1`sL05`rYOנi"Ԛq+UKyߵ]m_݅:]&vu]umO":35 3 IE $D?t}vr%M͵Uk`KS#0 ;{X>c޸Y-6j#wY0iS֬7 ⷮ\+=LAg_9q_v>?wA:GJ=w\vʫ7}e q̭s;+dPO]C|c\_(@zz+ Dwĸ4Mwr 1Ʋt)8//)cN>ۭ'T==}evOG(;%IDTgOyt^ 5/m!BKOO" ,*dZ?kN{. I$rdɦ?9%² PL XBʕ*%!" a%ʑI)I29$ILA4H@hn4la.'ղz|Z7"spCKmw!h'NsCZwiNc`^Fh @ VD_T_qJ]I{{h|aOVL)&6@nu@vX҂5WDK5 QڸW*J۵T;( 4S,'Kere( vDܚO`GsDRX]@6!pj'4?12@)Ykcܷ$ɖm*^گ|l90v I#zCL ;# Ђ-#09H|)Pbz%t9'Py\ ˗{͖u[`GWu϶|coӯxCn~V.x*%(REn*fsڿTIvu7N*+C<LUNmX夒rMTLpT]`Xڱ3;&agMr'`l Y}ё? ̜3[X6-X6KcǦmxf-ۿz#1Ǘ?TGF^_77?TIށ/]7]?kxksP)Wy ]ۺ5a#g^|z[\tdNo\ςe@4 nLsx!PMQU<㻶w5ֽi[Z 1ԇdͦmgk}[PGo 쮇ݍCZnU*'>Y ξrVo:prt5{ljkmkr _DA ѹ>Po}W@*2q[}R kǿc2t|kO F`5hk^s؍WvA^qށ=-;cc! ` :IZASӋ <1!! Y)QR$%X+`;' Q@C`L$9_ԿFIM _ (+qE_%%U{AN4dA#AK+B۶$]D0:"nݒWDy2#b>B 3=g=y35c]SKU$[/Rc=PIɽU2 F耫xS׋PIg2Cw5GX9cu.t5x7aG\G(޾p7X;X?٬r2uϸ1}]4;Ʈ4g,ϯݗA6;W4 ]zk ^<x;ڭ<=ՑJc 3V?vߞbܱh7>طs|[ i:l 4 sX+#āǖr/M7\XԎ~9/lӺ|ӷ_uK/\ 5i 뛟y툋Yڶ}^x5T尠o}{e˴(Ak -V+$/tOd|O({-ṳWq Ibd7}oݻvraԭBٽ8h`|ZsX8U`Mп<bߩ uDS"k6S|G}bJVBYde Y@~2<&{ O+!lN Oؒ_k&"C:PorT;7~HD0p"D!(ފںŭ[yF$IlMoĨA=oI?`g 4"e[TIfӥOlFW9TLs{.u_l~Bhw[2w.ckK+ Vh!05}) ,BC5'iyY]*>QG0' ߻o\ܚ$vޒY{&J2V[:Z?>uX$,=WͿ\8rcSs+M~z{@O{$9\p?i;o] WO+ ;z@]c5T ,W| ^<7}{לA壾Pg?稷L+sOolO/s>7LK$:[vߩ+kᦇ岧wGWc^pJp>t]7M{gىCpBkϞޖ}K[k0cF C AiNhOvﭗcGau^tֵ>OwᑕG=1ۻ/Of]Oz)mjԱOT.>~}]m_rKot%?a "mjtQ6<&!P@&+Me:H{߇I}DVT&yfyW-ߓoȈR-gt4mZ*C9@8l0\e\>&4>Y#&[AdPE鈪וokޞ_w.qሄO4m1:UtFNW[yj!S;s리X7e/ǕOiw4姾=hrASq,5- #~W>]}%7\l@w,3hk?Y!k6M'W%#jפJ`9^vt٩ksASqK^z⫣Nj9ڮ5hh#1V"ΔwS=% clի@7⇲BR2r_( yJ5p5Nxp1>@]zdܚ[J0D a?7a22`CDe 3ŸRB-Ymy5aT3BcEQWYKv :?rQKVrV5$aхfBW(wH%akNړ豸f0Z )`a0rA@ EcqBD|6wf}=e.(M06x  R:]\ccbm-!Bi!@غz٬ gωb.@&W]4(Yd5]T!C{h*:JWɨ6HĬQbKd_Yn>!j/\vY$#JD|=w(n?w3(M݇~'S?qP:Rnp4*"05EAjP y$ g4⸫PO7%tG/cQhܙ 3w*ա{֓WrD^+-n8/yW+*f`6F'޾pp~`8?Ξ6sb{oC]_ZINeO_ân=Z- 7~{Zd՞OYힲOoWy{W5Pc_~" o?鶅 ovִIЏ!"x8,6DZ]ey @S HPd\,Ŝ>ǰsR,t` BB !"N|7 (e(C )! ޓ!* W9౻Ekȝ 9?Ե!觊.0]Kun~֖-K+"Rz@<%K> WdE*P~daɆh!'{.L%%<Y% @b#ݹb46& 8~E ˜&@ĐV}3CX\AZ悦N Ni&,#F H usWu(>KPbro$^ψC3  4 fD\C,F= Wj@r-cȶqU,.tk"bbÜ5Liʾa8F(8^.@Bl${ջ7NC@ǐlj-eIqbY'y0a!`('[~.$J^y$ (\նRVK$aϋud@@eL=٤nB.-hrԹ6$Ux(l@0Ñ&4`X+.PW{QjGE0+)ET)B:l*qs{(KdDjU@uCP IDAT#R 0%砹0Gh&⽅W"R m u)0Qx(BtqAX&!U/92*'!1"E:#C%O% ~6$U+QK@i(ChHA2@^0׉Uћ= RYd o[¦W3QHc֎6DVDnIyk[3sF9RU`--PB] %B3#A ŷF0+ؐkj4DI+/ DFqk7DA1m`|~ !Dl?e\2Lknq}?ծud$Ԡv;nY)DH\0UQ2[mu!y3 B(|{x3( ,ۊE*I8խ 6Cߺ^ézU W! )E9YIӪ(~ɟ[!hFgnGK)ɅpI`QU5Y|.bR)[ίWSa2]G9PwȒ0(?tnGH&k5Y7EX摹%d ,0 &q tPRH}Da_aJOvи e} aTйV*0#̎▜Ԕ=Ap$ ê=eA"!1z@QJO jQk84/8%NLTҾpTbt eSv1@%ά| 9pdFA"[ ~Uw@aӶYӂW}9ݩV6YmK0J$3nz7S% Pc6W׫ zUJIU@βɳd$yi~;}!T 7 d)g#TURc/H;Ѷm$=2 Fl[=|'v^8credǨ%1All6Mo؝;&A^-yKvnYma&~C͉J#/5P$&1ҍ /Nݏ`bmLb !Е%jmbR-hD:? khĔc*%Z,5nɴ|oڪQ'(Ih`CEEo%syj5gjߋU'jDz_Q#3rtMҐse ΈM7E$@E3cGu|( 48L 5kf?`%А{a>1]S ɧfSs6—BONh2 9ZUݩKOؼ 9ϫKDmtnEBNfDWcU?2~p A`%d̶(Q:T掑DՐ0TR+{Fx+{a5ksNEjIᚳ!Wa(9N#k685%Z@iZeD#+)fUMqD@c;OK{Zu 1cN톂%F5t("eo(ʀ ǟ$9"\}uQj뒺WQ_3] 1x;6L"=44`Ld&f0N{[ɯ:͹ڡ оJV,k@F44kjW{ z[5D}V31fCG><kZ((T ,{KAjck/ F2-*k̠`"@ptO 帨╛IS9FRQ=5u9+'&_H-O$?0I|$qk5,F5:1X(G (\I cKѬ"9~qT[ \ Ha CZ`)'\I˨T9͠k,J$$BW+ӷ`f5e!W+ꧧ/K rIPj ť旟|֮ݵ{smW_k¾s\|~=*TzŒ s㞃}1"qdH"##xHX (!`gm1kCc1FL^~huB|!P'$/6Dt!凌#4dk{g=ӷӫ( ܤȯPݼ?\ʺ!ڐ\55?5]t$[?TMCi"2gމs{ jVVNS*@lH~^19P8Y+J,Ạ( j.Bzpf}[CDQBZMZ)UcB(l(\,A"O>$N/ILcYhe͒d7mM(ֆ1P sO*H*-w:Р$qjطO~U yo}n7o}6\~_s-7z #-~W­ +r ߽w)v,Mc~f޺:<41E* &=vہMo}s82[6t䵗μ}&mEg XgeC^|k#IO׎eFc+KY? $[+sMK|`˙QI!j,:t,<`c}B\eCܼ4`ERyd*5ÕoqӦCijAt`>!P +*#AS(Xa5K-O\X4U488)K=B9)D-l$Vb^Nn2`>e GXt-! \|ؾb <5 Tkmg|B^"_N(jXԗr\KdK7>f04^kLj XrLцHG#ר7ǃYx&3 hRsȑ]0,r`epf@ mJoccYT&aӘ$ܳ?0(QY-Apqך+JdŴVPh6U/٫Dx %PQL%')TتFtj` m? Uzv~Zd%30N`9`Cщ4٥-UiCK5|¼Lؙ3'iږ1OVD^/f6mq[8/ n0]v g޷Gʝqc "}lxE?vy481{?-_w}.޿o?f? ?&WW^! MR37K+}y߹oϯ=l}_ƿO?vGraO&*"v)>UiAPzIfXH%_L~0:@).SY2R;ϕ↚W6lUsk2lUe*:LQׯx/~!!V 0X[$Vv0^IÙ~I̍bcWms8p*ld2ْF =-II#0 BњZS ^h0C,˖f4H$>7j ]FK8l]MdHQ*D r-y J0pVEpIqP0afڄ̘[:poKpe$M~ͥG?oF0A_E}vRqJpoRTbG\QᖖDaSYj˜10- CR)D% Ñ $eX`No^S]Uwj ~'z*ebCzl8&A|M| >yn{'NmAbd&pX+!#-`(PGey.  :dma@mF)x"ɠXUQKdh~E7oF/9{^w-Ne~9Ӭ#|mzh#_;fG3gwXwխJtiӛ_Gg=c++oyss3_}q4~I I_pǗxBsrDg>តf9^֯f?vہ_{ɵz7FFk:g)s,/c*^h+kV?uQeYqI2WM}Kvw݃gxcط}u|xR)3g:`M_s fSמ-oxҋ2n(t`'`eV囅 Txb 59Z*)kEoCq@_oIPJq t+'q5u)ZL267bKoѨd 3sN!&nr#>\_ʮ9͙:PM9 kt4r.  l+X); a1EjG)k57`9ψ[&O.6[vGK͎N/ 9u/!@vQO|_ELӪz@plSdZj:ǢaK0mZj''3OBsNb8au c8p^M/7Y,_|ԥXCDMġh*l02DR TѾVOWܚhn}[#<ڛ>g;7W\a򭷽躷:߽1ڥqcywz_`~z9xTSK`wh?|)ǐ;c`u|O-`k/'O8 ~pn|v?3>sO'ѥ_}G 0_ ^՞玱8eЁ9u)e (4ڛbA=J0,z0aeb1u:D<5 <GsX%~Ifb"p_\M [n8/<[G2h1oUYZe%/~ rVB#p׼YP~ ߚ(>3& [*"TƸ6Dg,eR<IyvnKztGC&؆HO"$ms$cʒdfOeR3;LV˾W7W\f04điRh62k`~ --ji*l/&jPtidWxSw~Z!#3~VOnsh f=%ڴGWAĜD`|Qh0LNMEk!M5fTpM=idkNI] 8D+T9p\XUИLlv.X"Mkxf8lRϷP+Qbm^SCLp~ʣL&J=1'R%BhȾCb蔠ڹ׮wpbp:|vj>10E/ pʅCaCX= ǑNэKU}WĜ#*'m̍@F0vbkGO [VHPk@U mC L;̛- wKT5kC2'R|4w?syoxM瞞g޲nvt/l_~}fWL& a~Wn\tmLE۟[7Y4x3oyEwǞ=眴 v gV>N?̿v_K{.>٩ѳp/W챝P]y L &G/\'KϹqu-Ŧl&QQhӣf_\^,QO#E)w98e?-Ͷl'S֊q)aNHpy@ދ\jH׋:kXQ_c2朹gUq>2ⓚf<ζdܹ\*!K4E7D|Olʙ݄c2y?RyI绽#DDz;YE3 B:C*ܼ$jv>gkEd.#<^Us95b3CV{z2DFѱK07vQ5̵=+D z(9b;q7x^1$(MF< `Z  <)y1p۽?ssc|ǟW._vl)cno90 g=< ih~GSw.rJn/}ۣq{mI{mNk^_}%Ǘ`b&`u/]r=[.||عgqӎȫ/;|V@QOv^":uˡCfLhj0"/=tR7[$jNBH w.+Q>v.)w*z': ;:BUEEQ9Ff̴| ;n7&STPB98<^Q^ZbKi~ O(XȻ5t6$OGJ/̅,=rd"bXct(Y=EF[DԾx96^ RKyVk>@Ff*;81ڵ?\ NȯI.:€9e@h92V8 "ǸkB̬pXAx)K&:Gd&/2x<"y"lJ I**>4W]3w] HE03-?5sj8LxfƱ%4D pJɢ"8X_;* lѫAExb8beAdzL(QdlЗl 1ykHUvHؽlښS&0M==!#}/zu }GQ~l&"źG,שR%L5 ;JŔRZ"jars|,)[`egPU GW.|ϿЋM]Ym?pƩ$!߹1߻錿,')ˡOO~gL!=ovCʷ)O=_8ϼ2eX?KnԷz~y'nH8Wtշ>j8H/mQ{}ǿ=1~/92e>{@-M~/[hf,A\yڙ- 8y/C9MnC~ UrYA=R]*MQ"I?oɎ@ T #YGZ䉢 /N+`U4ah5w1 }srsb5td28QXþ@5dJ" sIa+.X~{D)<Lc 3%P ]i>a*m9:n>e5$ \yH l/t 'ߧdw$ZaKb3y#_k곚yQئ 9%7"f/$ :! Ϥ1L8gJ֭piG%+ ]E~Q;s> j=fŢMZ7d7+ö 2XmL ^]'R@8WqtSHHyMizƒG0>OgV cm4+NB(;̦=Op1*vr2j0,H_aؐ6Qlq ,,nV#MZ\1v>LsPhhGPH:lQ +$SgmPG7r8=jzAFd8i)P 3}x͕3ŋ}oo _q~^wg{q6Oj)__v_}+SMǫvux`S.o,/EYOܱ:7t5g]L+ F!鴋rhؤ߅"fo kԈWюBK_p!*GeO p` bp(P±b>6 F(+E~L9T*PVKf%CPPeV okZtDL%"UMC T=ƲXC7ĶglUx˽Jx ~/C)Uf*+$H!*(l戕t_CU)9aV!L* ŷ2T{Iա!hVqr|lfЏt¢eDXZM LM)Z:l]il#STI!RlE1Y(-Ҝ|I(ӡ-: {R*) {սYq`O/h4,A˛7\>&%fLDIxA-VsAqIzȉ^mJaWc.h$P9TA B\}= {TOU:!X$?P L^40%-,  iʀ]^wt۞Iw깭Xsسt M:zAGNDhV7m4W^5έ -l-ϼwlSlHHc׆$,٧_w-ܕvXvKS׎ƃ$Yzw}O}`^+SopϞ K+7߿Ӿ`ϔL֓ڥA]Un}xkg|<3O='ҧl?i;_s՞~޽1ya~ye4X%7`C<X"禱pyݔj]Ka4ݥ.C5FmÅ`o~+ˀqһ:4|,aCx(4@-'3`WhgR2j3[ ːR`HB%Y1y=W\"dT$Z~Qhhiiu@FN0xT$u۬fc}4nyV4ԤՒ}N*'=UE* gK)y"gFVA y $J.pHש2_`]䛋3$#KL'"E҈`/t.Y GM(knL\,OV䮡+uKph#pr+O!Y 6G*6 l'In;򓩩'Q+%<2s!1vB;ވtb}'YI/j$9}ҎO?Ǟβ,r!@ 0pⱿ=u~e/Kt)0|U?==pc~/]0ۖ?c+~+M~{O|+ ˃͉n\O;wm/=>;NY[߽얻d6޼ؑռEDY\ff*ThIƇXjT)dB+y"me4uF[<ԏ~czCPPw@N4 xhCx>SM[ϠU; C>C.}3{1Siuv`n.g7jRpP1Z}3%uUwbՖVN2F.B`[dP$ނlԩ5"t' u-:td$=s&hj8yk<}<4m1[;4:j'"{îP(3VRdq )YC">L$=h[CPNz^Kˌ|_+83vd67CS G/S,#Y *Y谔Vm(Xl2.Zj98Jtnd&"y $1YH1,7|BƬ.X 5뤞VA)[EjehNFWq3'w="Ք2;<X?GQd @(]IPyr 1TĽ,V+^#)vmISIXb3(wMnx0E3먝4Ʈ;ӮݓC[1PCQ/5&.J҆İ.$hjeʥ/ aG$C:F'm@EQJ9 8}:ii4cЏźf0Hhic`P~\.v {L /E#4"_Rf@Z0aQSѦl[֣dڬr0V˶FvzVCׅ kXuNfB# Nj-;rT]omK*C7aq.FQ*h=pЂ mL3$i5NIjMyk.xܷg{ǿǗ^Kow/ӻ,ŧOy&5s9,ZqMGw+nwSV~nwh<( su3IR;~Y?jΌ;-ܷi>\׽UW//oZ\MFܾCs0Ǵqa\r3|sS/<{eW:RR@/9  R8~4[t襺el'jFf4yxubrMT-(طBh#%aPZSY|B|jNfZO}gb${"gg8UKPvϱisآ9)>nhw!ވ5IVڟTV!H 2,qvr܂Sa&a !X?f`DF\p-Wjd h6Z@/ xfgw%D$}p2l+' Mh8-*q\ތ'FbfS}$ǃʙb PN`@!'}oG&*}MKEH*_M˶P'!w1KutѿQ- +ftdOw8PD0m!-כrT.0 ē Q6MKlیd5MU1CfPo t㎓xiO|jO=En9]q3kw_ b4iطx|eh2 ,ǾsݷO>ǦW-Qu˫-/' to~s;wm3|s6/i?\w2$K/O}+_wϼs}Qt9?\C "]3 uW$dLWZeShZOm4j\Kb'IDATz{ l)XL/0Fp[7?ʋH\<+G!`xaT!md* 萢%D9BImv8@fxUPjShN jqn60GN^ҩB%XEu;VUF7䮃yaz:|.9Tm=9YǜWNS'E9x'̽Әv ikd8&'$L ۽I`4Wߣ[h05#n '0W{Ey bit|xh)[rcLv%1籸@ <l&oRc<"4ښvq~NvAaa_)TG_)az纮17]h >ttN1)D]K(Q,JJ{t#+enkֶ y#Q^#B}0BbZZqe'ea8_J7;ZA͌d 152фʰHVdH&rd50yOd0d%*:@2<&2iP!GkwIlh61(u e%/Jqҝӣh[̯zn8wljf%NaI У@/(8r>ث޸0G)MRvN@B>,oC|W.1A$427gpLs8k8q -fVʄe54&B?uDTܘDžn*WTiּtR *btf}E`hԖ8 s438i=xQ jk ̾|NhF"02Z|5)ȹbEjߡL/HR Pp Q^d%ԔQ n̐ %20 /,3]&kzd2QؔPھw&m,Mc kF<˼)Gb4Ȃ.4'-DRNqfYSq@DJ5ºQB+ZR5-ѠiHkvp| mڴ$*VZUW`DS D wCױWP;fK;\lvW]ׅ[yݽyY?>1 L&) w:ܴKL{*\: \QF~Ç*Ng;$Be]^lM+?#D*P)Qqn5ү4Ytm K5FQ>2 z8Go":'eg7f`ؽPdZg}kJa e1ׄ5B_Pc͇=irʑfea<54D,ite+ƌ7<::T9FI Y8[Ȋ$!k;7х85)yaD(?& daϩH *QPEV A]Rj1dGAC_"bjviFn=&w21zoMJ<Ҧ~ă|%tbLlnk .uZUryۀ!!8kl6{GJlS1 StEm,I5xW4U?tʁs]c[k K o98ǘdwlه&p4h)L`.0ang|xNb"/%T w|{<`o1^cyl?3cVO=C}u;}y KCGiRv&cp}tPXSQ9ci 'f"T^.2!WP3kW_/фٙx暌vhF=wk`@ReWFeSˁ.h]HۆS슋aBA kN1'(i6t3R1`{vF@Řq4f#B¹[b~ dNIyruԌ'/Ϫ)rkC Q-dJ{qt^fs_QH҄\ M¯wŕE/RjeRUZ!D.'%b=gBMriد-w+ZN[UI73ɸ 03{}RD !ƳDd{ᖒ*x~&ZU\}ݴퟲpcN`>-q^=":i 1#KcI 3شM#KsK:4l69'Yy-mbYAq-Dw:x.WD"ʶ,։i^eiU?دiL /ƩJuNÌ*B#ϰZRG_)|]L*ӊdql"D ;wFL'P@[FM%[Q~z(5nG^DԀMۀr&=y OϏz; Ȋa*du^;֘HD3^`jTwA`V0xu:oTAثhtE 3/(~G5582O50HUDttfyЉ@éof؁RȮ{N(d1ӶXeljCjӟꊛUok#)Eu*`*W!?5&Ջ>64lZs,dh{p NU(պkM'a(jDtⲂ-4a+ t8Aow03U! L(VzIyM:CGDI:QZ+xVLZuN*ksI:7lw:MҝN.Ǎw5 L34i8ٶ~F1n,&O^q-hu 0p_;tN 5)'kClmHb >_VNw*V_JQfq) W'ۮiw%ȲfuǀP24"@a{S3,)a|N(F*umJƻ)l)Ѵ)˓2&UaM"{\ Gq 1)*_uϷ+ש#Vw͵ MJ=y'Ӵieܹ; uf -Oe|Oqs 0sOD}PsUt[:c3 :Qņ'č9 l?z 6Q6̱yAsrٖ5hJ]kc;=q"Wߊudh۪Ne艹 v00eR ;vQʓ>uV_Tq`9 dh׸ݛX^CzF;'Uۘ|5a1̈-X4P`f}8S ˋMɀ]U8>)\xBq0TR]:>8&9RΝuf4#50ˮUPaVE;pj(ms \|-#|$A,DS~@S$M* 6vs}A)evexQA}Oq0}EOh 1v`n:px8Hk`dK^NRԡ56's#ie[,Li \9\p&r|iXmVv 7nhֵ)rمMDi޸eھU)`J:Pefp٦C+^v{CJ +$eHZSybnOmDggk [>| tC5iy%^P\p>jP$izf96֓[ (<5,<﮺O'|5fzp`6+4  =c4t $fi~׌9TEڙ2Unՠo\֫0=B& $?=QZ2Gō( u`xSU,Ri2ዞITmqJqrI}zr'k8+gW*:?o5i+TZ_,YR?RջFspgu[V?{pӓؾ񺓇D>oTM6/ E1 wHkBS' ܲ)yZ h`dj/#W5 ABJճ > 0mOSKؒ).F^ꡡD 5cIXIBւ]mAdmD;pX=ҁi'YA7{.Slde&@f`Cxh ֋):3A ,6!Sd2bߡu5H4=䧠{;(@xn6Y]WtOLLIM>̔/]iB&{)]L+V[aj"y`u\,ꜛشPo!RhH#!,c/F:ͺ̠p;BfϞB#Uх4DGgJ| .[C5`{AHhsrf+Ɲu@9"v`^`H6 ySIENDB`dtkcore-5.7.12/docs/src/dsettings.png000066400000000000000000003620461476226660600175240ustar00rootroot00000000000000PNG  IHDRF" pHYs+ IDATxymWu'[~{Oo' h@ Hw6]tW*.ǩr3t]SMAcwlC 4! Hh;?^k>I.{5ksp@Q_zzi ~[Z(Gu^-TED'XsUP$+{.y7TGNwl~_mG/_~eyAvwsz1u'[D`^贈 _ -d}IW'Jm$XL bc@T[[cGkK^y߼;=yD2q?%jNšF@Pr%zH`'^q}߽DE!*-OT08  AsujjA!"5ADIà2 tTvO1 qP\2b1jʺBŜ\j^ew/^\*NjGq#w&Cm"9zjVrT*àqrX1,^n?r'^iqLqaw"-JC">>0b<};WXUD, B5 H+"]nɍN7i.V*4Y|B'o>l,07FG&VjUP@ lf1yC=$?\_.NؿÚ| 4!;u&U+& @jca$bM1]Y"h Y3ԋߵxfBbS  %(dq0 gc"Q>gbIKoҝJ+']{4J'`/gk{Z͎AńpI$56~mr Ԓhr3UݻS.QKI-ߚAp֊1 ;X.\3'7Ol/?w'տ:;_ޒ7UG)ˁRuBH]TSQ*3B0S)p٬BQ6Q*Y:Ĵ^JK"领ЁKNhQ,` |O>^ m` T) ^U K RU#fEJUuU֔v9b*$XۊՕCq?VTwα縪q. >m5] WnJo}|g)ۗ *qWY]s _ٓ{Խ, 1%@o$O>xphϩ}89;x=N䙓ĽEI Ԓu5kNҎpxڒ66RǶ1v.=ث7`#,_'Og R7Rڴ5, HBJ 6 3)_/;`P3x@=؄ V ǤcmAVufOogǭiX74j{TII%/LARMbn+;H2%wɯ4юⰝ=::[zu37f_3\~ 1iBZ~ xOw"Q0L36vp%͟JB40ԍ%A9"*p+2Tb;"^7wjԷo(Tj] 55CE&@|K҅QQG)uBV/bb:3?%CdΑ4SR9:JH/ࡹs5 8YHDwCpONw"5C6LЈuP0 />tW jGfwp;LJ9EuçwʽDl|KA &G1EkA}v Gvđ%EYZ <bח.W:j)(UBR]V]3o) &r b~@\B5\D8*U1EZ6ULX 7 {GH4.~ju%/bCV! {'hjk^²Iԅw{zJ3Kq rYQjy^9MeO7'Ƚz;m+ T2Z_EzV}ά3SfqRPENZLA||2X`qS"?mLrp7a-YIIY h9eH⊾%J2D#>&Tb5bZJ0B&ZÎ}X!A5#Q: _fX;j/2Vլp*MPU(dc&XQσHuJ=b@Rz,.F(B>nhY3hMŒF[DСuF)(F!>ģuPiB1TU *":J;yVG3.*jPJ^Y2`a\g|CƦ1ՏZMb@8قhK5)QP voPlj%<(Quo&6 LÞ'j5v<]]O `?iAfT1>\k7g=1UED^8mt- )ORt[jxPN qvR QmxdTԏf\ _:O.d]#EB:8Qy>>O)z¥\#- Qu=ElW$dN 0n,0J,u-v 3 1.+xF(2# ЪX*# ?d.j9|91-C e9I+b|[7E<<R c<1mpu5Jy2@vX J$tk1BUr\Yn/.!Ḥ[ CE&ݓ%-3ht`r'&>@%%s-vc"{Xš+J3\WfOYLEK"cDDں rH\jǂ`?NYrQ{+&:'ڠ/lv7uDOXӜ4A1֥~DS#u1%%77kfn&PZ'B*]&7I3[0G[a4$hjJN5q醶* dz#~ rHR}K(d7X&!FIBifux81ه0'O^W;bЍxC d|O1C~YI<٣iπ0ȷ+BdDPXګ-P{Q\r|DdmR}@<:4mXܒw\ed2ͫæ^1 Dl鰕hS<RBĖ #v Fq q2bVuA!s]݆Jd{7C_Gb95u(O$EFJ@ ڕ3֗0ZNQVo*HP2E4XhYM% SIĪ#uDhu$,v#> )O%7aex˘#>l7SHk2H Qak6pc!P{c,h6S㤪 Rh'ۂ<$Ndyvzy&jQFk§e/c '0,]\T8GH#mY (ȕiw40+ɱLl>#E5VV:oYe\ae,g}][e 6tjլS>ꉁY лv/;G.AṬ b?,6CU?;s)&&2`nxr![zC+ ~y?\V(gGG5^ 6N׿IyAǟg'Ey|Ɓ447Oꄴ wMN *a!n:,~xbyAdR&mAwGeV^?SĄ7ׁ=~W؊BuOu{vz!4LYxD4#7bN-UYǚ,ǺBPx iLn7Ib7u{38S_ X?/iTo]&w]cP/ }~Ny裹 O|&5$M3πy{Q {?kة-SI04tUo bvJm2n#GضY|){(8m8 +ƒ IDAT;uEac@1+.f!h910lSȅ{AyxO]w`U4 86԰ jt.urZj9K $b/G9S/еɀFt)O$Q)g d4.#n&< + IhR?j$EN?dc+,sWq s3B= v5Om2_kha1`g*Eb[0 C-6 s[O:3N=[1$i&/Vlo]ȭb6BEz竻y5+3Cǰs߾XNrBN?xsy6~Q윏ѫVGMἓO^/TU<<խMUމ >c{_~* _j˷Uv,ww/Cʧk߹Hrx 9׷?;yzS[MEVhač[…G̦|*ql簽)2as5d[qzw݋38q*=O?tڅ=TY͏o}x+*rM8wK^0z#8)w_=q#39;Ǣw RXvfe.X:+ROX ȟp7'+lHX.:G@%#Noۏ|2VbD A`6Aۋ"6嫎PSg5JHTR|)(?*J=)XFUY-㨋3QǕ4oG;M՘$nC:RLUz%JZho&ص-s@#%""8%zҩZqmjzz,8E.+8y,7e˅.j08n\b{/;{PKmVxY\4!'VÑx\׫7z?rFH\ e'5 g9'=.<~H^{*4װ1=O[E3qSDU37[ ˉ=937C˹#_J>|rWWB (|r`[q+۳S߇?-Z2@A[??{`з?+>qpwމ>+y>t{ ?r6&|3xko#.b!}8[.=˺C>|z/W_%N}墣x<p7᣷);w+|M}d7CSqs9-X4`S֪5QX0pUnӼJ 5LQ؍Ԏ>nV!'-'*PPGF-ʆ2 A Y@@0+K ɃeQmM^*0nZ鸂 GG2 R48j% g4Es;L$س)T/6Z|;[m NrTcjOIz<r& ZZ`KȖh{phʄnN+.Iynj+/+.Q[9+dA53"]$U9c1EՖ'AQdEM9Bs[c7Y_3u?,'0bTydV Ve)A=IKbd9Kr%,rs Yk7e{Jʃx?WFGxe2OI!4ԙRQJ]aSV&UWwȪ(Iz~W;p=[ += ۮ4\p-7ym߹w #5n}H\_j'矠=*v- ]WkD'v/DZk_oɧnSՁN_} ~\z~o.'wC {풄ᑋGȗwދ-Hw]N~|}{q xk D:͵?|!-!RF|Pu}Y]BEcB"}ZۓhFq̆S(*R@oZ_r͇ 'M>*X&W6#~9'!ro"MݘXQ9ciB]^rS3"hS9Oғf$GU* c>[=f./FI/FFee"^U$!#"bպ,]=M-r䮶ce~7J.GDҀi~3obR!rfRfވ,PS ]6%v"l/@7CqĈ53Z @#UUiΉq%s:2b.t/sbM|jpްTdv^ʽ]eo܁Ƞq5auqdfl Mz\8L\5Qؿ (AX-ui+$6\FqGϾ#7Z/SoGcEWp~bC3بG^'o@pQ.X=gVs\\v%.W=ʷ/HAV3<}Q_ߺX0+'XI=brlψ7zp!͑=X B0-ݱij 3%b6?#|۱a=$n}@ޖǮm _?wߍ/]]Y3x냸1ݿ %0ߔͅ.f hyYQFۍو[8s'h=xBozw[ 5>[iSP!gf_%vE$B#<=_,lSͥԪVFH-%.LO!k+ \.*SGX#Oth+G VbHgt! TlA&gT԰^em+?R+F'xBV?abLnbk:IBט̩10M*aztR%/ۇP@⾝ ʋ@;KkKjlKJ_+[cʖ=Kwz/ Mҥo˹R|igspUiH@ (,;;i#1釫:A5G3!\'S1$0#Q%.h)sSb$;gp?b0 }/l$ބyβSA Ǖ,ղcEǔ˸\TiY|olo~9xw;ݳU*rac7?o]c!yo faz\3ܒŽ+fRo.u۝MªaUJ37+-2YQ }e._]}}nГS7&r, @tݭ7'_[72K9P]u[P`)l(P WqIs?ٿUEF&B8ֵa`=4=rZ?#%YfĮW#Y&}+#D>0Z-2 Jl .#MKyCmAR ))2 ,YP5JIҽ5I'ܡ-KKsI08y=p|x46 +q\RRʧSA]MX6j/LU v[xwJO wmmJbiM%ˉ򳫮c 2i8:FRq+%' >Ea:Qrk̏PX jQ (iB[%lfa-'p (fW<^)\splѽzd3+'f$Ē"_1czC'pt&}!+O3a6F,LW'v⛗뛾CrSzwiיM5r-|Ui}7^/:q41V}]YSG)CTtT7٫$K4* @Y<51bnEBŶǺgIoe~)<]|:1r!uVSM8PDŽyH+ 4h˙Nj6^о[wװ17r_46iw:n@oھ$V֖ N;iW#v4F>Ӑ$hVľRCb>.FX ,}˪sudl;bK N O{۵[N;Ŭ8=Ih@e@/_7ܓr37bf@u7oQO߈?וW7O%'UVʑDZ=?>n(xer%rqUnOo@J/cRy|:)_ods7/TDk!B?}}7'0r7jw߭6}w˷ߍQɛCOFG_9 }ex2Dh +w[*WV<5ko\+^ѽ_ީw]%_$+\ Pџ^. KTn}P+~;;_{ D+c@h#byqB+ϸB[+ojAοjR;JI1SSFWY&,WBT VGZ,AFb849%K}\N}<:= .Fy*wք7:By+0' P9j65/&SFJ5B6X̷Ocl>';~,v$ ̬g~Z hꛁj4Xi΃{bƎ&di*l_=u1ޔlM(pj˫ΧE=͌拮i5eAIMv᳤NV{!,AC!}r69-\m`Rip'A`q 0!@c@:iq5l6i!H/hjt/k|\0{@"">{ V.7uQTq1rWL]N㐧.ArM3sܸÐyϟWr,H>M^et&4yss+{ct*92ɖ~+bU IDAT*խ KOwnfVcvܖM 𬯝K|x\|ud&x[^hwzR&™eF&)ً1 szY-CBspM0YF׹ GuE.#)O\jƇ[ ,ݬ$~|q1m\QgZ)(Qi$*䘹Ҷ;I2ftJ[-sfR̄':toZWx`[sŚߚNނ CYY@Dtn.SRd@o.mApŋn^5g7AbN͉7IES5_] ml>N)ztwBXA]'n+0A)^chDkw"K~eӬi0/ B.::+[9"\tM ,61JA|oIS:fZDuj?Q ë/=un.p`xD .)GS C=@'h )Ĉ/DMDDoV^h >+x&/(m/ aYyÈ gSIOkc"Ӓťh;H cpG_ n|w_9-Azhcgr#[ʪ~}p=Ð sh3*9.%.PrZ+>+L1|׭$ND<ed6N7y10פIܰW^m`6Yź y% Yx' r7Q(h!Q{36ME#"ݒ\F_rt"3zZm̂x P7OW_VgiN9ۢ*w$dB*q閦vby]2rB͂]Yf 18pH-KKׅVΡI^m tUuWI ;ye q ܰL!% =:GBAVK?12,.әqB¦i4 ]kvf6э{jxG {x4Yn|c SUgs8H|%?7S4ٱT. &hc6)8R; | 7 Rh8:Sr > ŃQ)Fmməo(È<|O-yø yr\BI"Lj^58;gsjؘSjXS>2 Y H%BKed>+-O4Ej5C>Zbink *j֑?,JI!*!C1V(lհukzi:EeJ h C ef @VLq7k.$Ņ"򰚦.7q{GyjЭLRs&[u.\1"b_vm v”ZE$p[INX,IPӳAj{"m"[G  .8DʆkMhmia$CHcqϪF.;*htɬ*lꊬ]2//Iitڽ1@!ƭ`DaR|1!J7C07\f͒h'\959hGpcej[50ZH,X 8_TP _H"`⶘G qU/_`-ď[d;e\])kEY5w/\OU/HqAo9oX"bGe'jE G̑tfjOR[ܞM_Qhp"3T<zտ ~G"v@Vܔ๞#== %!t4J(a",>AhQFp5TI2$sX6k(12Kn&SIgr؜ꉄMčtz6EQV#<)@R#Kq)drݲ,Xr6^$ȵگx0Ė*yVZ[`)xۑV.)v$|"Zym@p:xyTՓpGcVK.5w4ٹy-~f%Uc=hf7hdkk$1&e YcA@w`Uj՟9_I 6 NOt=By R@_+G~(WycF4 Bm [F$ĎS iמt 2~4%_\ \_5]@!h?^c=Iߌg}M#. '?" \Զ>=Riʍ] Sh>x@=f]s'me#ͷ&)fQ/FZ<]é16bY=li"pJEsd[IO\GC֘ fBXI3خঢxRFҩR\w-R۝37]Eha.")ͤ?[U as8%m18(vV vwfPnB`Lgզ]jHz%fsF@Zald%s0 #lI]*a5 UIY6:)mMƷ ӓ0Ś[0W4b0([}Q5i$\%gm%ƫR",`_Y*BAYTtacLu-1lN,T(`\k:gzfvjPȸ™+-k"sK2M$ױDƛd])ۄ{})絕v#KmӓVvϾl}} QNu,z62 J_<0IsBpP^OTWܰA+/3tpÔ K,xClTZ?zrͥ 5߯˨\2M] ADJQuؒȏp[J]0!yq YGDjn<F;1bY8q5"0tF!D)g%.OLCSUAO$?BR:4,~NKKBIJWl-%` ^l J<Ϟ`S,j K Fiw pAu ku@Va RQQܥRH0S2#}SJ82;"1$cHu?,hե4$Q;FPݪb4ޛS`F[,j3̛& 5]x['71 ff}255Th]ǢQ$v@<x wq8C.MnNxxvFs88biܠxH);I\$ЙrpAiS v!Lv8bDq*Ԟo#h?J6rKmDt$(~ctRBcQhSj!9jpYSEƄ j>ZX[:njR`gsj7R&ҵP:]i4-IpkfHYRdu^n`S-P4lCZI?AoJ55Uh^J͹"|΀ĔMFNPJuUhUZ,\LM?.3H@RNP9)7Us,ƥnT3 D'5E܄/peCAm u\SJuLJC4@*؀I]Q}{"TgIJkxU{0eAZVFM!#az%œ%.U rQM쉘8F$746|7n˜҇H41-Q`f^~PJE$qEH#("| l?E)Yn[:nv_,W3)z k̋6Gxk:^@uJ:傲:V[Bs:vQ(wIG6Mp!-%B%4뉧 itW8Z# QJ%_v !KȪ*Ќo y,fhս  lɾ*N=1bD_X‚I)m\r|0UrC%jV=R!y45֚(gA"Ne;I`YP1B\IaMI+3, ('kYB+Я02vrxz[/a 0-:zjPIL:罂o)f+:wQ2ްƒ uTF:UkݑܡYט\Dc.4p+. V[N{QE}:-[w\8`լ8b[Wf:t."E#I YDkfTfP3D<61 9]YUǹ'FZlJIC<:SZQܱ/wo<_7'7':%L`HfcDAY@Tc,;8$vEP1 b,:u2 ~'w޶!wbÖD: 0j¶ԕLѿ55![ʬ/IyzE.iGU 3%(gkW3O5[Nn0D{EyS[~?jç ٜ7>~GKW^NwjkO{f;E|~c<F7|볿_x/ڹv_Bpd$usbg{|1\.rA9!WdY;wyeXkw:)l~郇SKBD+/2e-߄|31Բr%;W/׾}ϗfSBէJy8ǫg)I(PDB$D"',I0~L2XHPBr|S?g$o>Lwu媮ŪmKxtCThƏxoEkeſugXܳ[^--x'?v>y]ծ~=gK{_^ϟO񫯽kĉ$ba•z {?Q-ƇK \*l pya-A;mvV?GUx5~?kJk2T'1QvGAq!>eV14@N0ue.vrZdn '(RH6~yA:.2 Z [:RTSkJ/iMN& }tݵܷ(h󹣸"T( !݈H ي aq*WU_tU6]b`agytl@2Zy1KL :(ac5p D Ӈ^6GEmLz5ڜHkWW,.fΘxGW,Q݇niO-?`*ex$yooG"I1OGw[ [: Z;-ւ*n8Ő|d5ň,28x]x@Րxr窗bc! IDATȵEl-P+rK1(0H$fsFV 2buG3l`B& `ɢ..1\ Zi$8ONbep\GBG @n9p2tb1>)z@:*|LnZRv0Sݫ7L,$|j!ߑ' u>ڳF1% \=)d#b,t߃Lr`+>q(UPb'TaZ,ل8"HP✚3-?nTfފ_??ma%E]2;7k,3{uIAοc1㿸~k ^?<=Cnw*8Ptb?RnSt@EWPVEGc[S[&(GE+ u+Le_3lݶʙw~ :Rij\ܞLgƶP G?-)=O75_C*w;y՟^;78i.[VT4cΗr#~cʡ}W)|c٨{_=ˋG#@[{"XlƆۮ\K_=l`滾^A"{N<r$ }wT^뚋F q<΅_v;rscF//M‰sWSn}e<+5Es;/ N|ݹwvucq6յ>lj6>~k}\0VU01+9e;u͖~O˖nء1|]^>naEоJlۮX?I׾[I[V|Kz= d jH>nKw_Rճ̂,v$`f0HS_ٓЙۮXzӟʡ >q-&oᕋPBU(^:}W|`}vAA2˧OijOS_9G>Y&7 Z 3~lucւ>FyiѬF{/?__voXqW%~Oo}`@?\O1Je .˗<1O/ 铳9.@[ ٟ}yш#ꮻ}ue=b1|W}Z.4 5MEd ?`{:q+Wi.,\|ra@Ywl_>;9TЛIllsϏbzWE\O<$?5+ AT4Fl Ԇy@[dBݡO7PDdZfef}wIljd4Aܨ=NH7"EۜC83鿳Yq̚Bkhh\F䘈WE_ڂeFuje!RDRT+͍Lih*f ׃-nZHFr>F#*AX bA]F b2{N` K·L:Ԥ1߲sqQty1P]rQ"j=65w$A>ήD:ʪy{ˋWY04=N;z:#伃 %*ZSKR5~qaMc;+8Pޕ(՛+>\?5C`Wu'|Ҿ=) )oAh=y'#S'N0 yJԖ=籼8>}vgޛJy]졹+ t,RJ(1o LHdAl[o.ͩ ?z-ŅT?kO8~(K}ngt҇hWW8G_@)kgiw 4?k/Zm°il+ZR;Ttt+J;?\?5CawM'|z.3veE/w'vp+F8giG"׷8ӡ@W{1?bɀ-;ˋ:҇Gv&K6 Zauޤ SC_r W9v/zPdNpF|;$J80 yJV&uS/c_96Q|z\=8L9! D);Uv+ JR30Q^݀ Q)% T㩌}=5Y]2 PgH ԇNCC[N"]uVDfޑbV h92^7f2moH*L%mPFѧY xO:0Ӆrwa&5vAQ$@va! 1p[U6F,زR٫GǀM߹h <=,+N-U V}>= }ڝjB`X^W[$GoWQPIJ> ;~{doEkO../1+p]] /65_D(qjP8cܮx` `x Y$Bb-LgW=}~+^Ɂdܯh۲f>BбWY{A2qg2]zM~0@f#7]&}vpsg[,+N頋ZrT av "'[5e]X0Hgb1=*+ڊ 28ͻ{tI%rl `.\;\U1w/Z>gF@ȣ//zrѯ}8eЫ?>/O%o8⵴ :F(}e9?+Is}z4JyKU>w_W[Wj3)vec_>u7YOlg%貃tÀs\TdYm4ԑ{}68ԞćV5Vh={о 9_z֬HL; )+\n0kis|@'00.΀UP饰VmC3%rm2mTWgc&F4P,#EBʴԡ$vUD~eJȟ&_Gb pDLS1\9Ss֐便+<꾨gժvW 'Ȫu尳|.ii@zw?3Ù&߇tbk7_1iчl6HVQ !5oLgb?~_??#h֑GWϜ4'VAև@ UߞfX_yPU0{JݪA rŐD5 A00/j9FtC9TˆmQ6EU\tpƽu%kvW)W[yeCj[0ӭ*4D**k.__:o5廫vW+0|oM=J;xx#;SvecKLHbτPXޙٿ>x`h.@{dDz QkG{sH&!*D6KC5$3)ê^Mcq5#׽lBMcqgWlh@?_ZKOuc/|ʤPRdH}u%kwה)[[J[5V%c`$d,G 皍\(?lr 5M%uI\y(lӮwٴ@@ͅJm[_twmٮ}?9ssמJ)Jc<޸OU|ei&m2G|ַ>"8o}W6VX4aͅJW_}uƶ>x='W-* Aµ2vf}8DظOKGW/He}XxS{jʈ}{Jj6쬜:jokg#s߫#dl#z']9=I"LKk6zAiC qh7䢔ӜFʐmyXʺw4&@ ϡ(!bE%,v3˿fۅbL΅EbL-& E*ׅ oidz1;a,Y,$,>R@?#`Vހx`OM!+Lm/ G/WuDhC$I"#ZM0| DashNԴMd4Bf|AQ ٟ# $!`,Aەi0])?e}p/ie{LVzx |xc鑕m)GٿԣwN0)HflQA`S{odƦ[.]>આn&t)ۆkRxe˦+mK'wу+[U6)MM7_|xg$!"^ew\1_SGP5ů~8sV{>mgMzݹkX6r}1\Yz FD/.Ȧ@ s֜1y[Uy7\8s()DDL)}¦;l[V42 3q6XWY6)-`Z0yāO_[ճuמ惵Cחp 6awo6fg:i/c6uM4u}Elms!4Y0oW65eէ}?K;+{lMKؖN/>ͣV1$M%s$Fvhל[hl-gLhƛ.^6> gNrikLgZ1/ڙkf :uMN:_ƛ.]:܈|WIUEˌqqk-*c~"{OY0iaeÙSOS&m[gn>Z;uE w<3k}ל0Kǜ2qG""{^vɉNd;P .5?XDEtYNI(1= TӖ$Q V0K"vyG)?;G{EwUip`*T:ȁ@)Z1~ؕUm P<G"or<3bY)caGg:Kv44C] K>~<wmo+^C6Om|/˾tE_텀/~pTSkW0{R}gϡjLiw~}VR}}m۟:_]֯yˋGӺrދjl-~fLwT7GRߟs%bND;q IDAT߇?6#/}8OӾҧߙ[|y43v S?֙ly9W.wזn7/+J}<| ;oҧw&[[fuvlA+hLY?w?,ÿHר/9j`9}aZw=xj`iY?**ȼf#oN1ag-]w닒]e>5Â[XtTSkW^JpS:w<=_Y4gb1%c~i]jH?ʢw?+Gbn|)߿r/][\K?LwyʵlB~^YQb#d"3⢱s_1DU^?z|k0oGlm5y~_[=׷>ޙ4"^_6jڅ=ⴌ+Hfӧl-JeGo?^yoml+sފ8sqT3ZꁗeK>ݽ=b(-;v7oհ& K__,6_ՖN6eS~%KiiO~n_~`~(o~[V }rRRA_RrFOJ,XN Ce9nc} &l' Dde0Ӆ~N{X i&ꑕ(\W}OMIؼӄseSs'Xߓ1v*ȪQ_nB/[Wrk x1< 1rH"}Z(}~gg?¼1_Y7('o"Ʊ҅벽 n5 npO9z5#DzH0G CLB^R+(LevTCkDr?Z =\qiZ;d#"_*S">_?xGO!!J$/,Ԋ̉UΏwPS+P@3q[)Дn D9'@yQv D)ō 3PhwiPe H,oڍ8 &B~#=7OD@!ٛ"袡cbCPh(DD"J(D-4 fz$_5)EWCo& |w:ؒq6q1.KKn\XhJUpmO6#Pnжc6|leL:ir!#!he+pݬ2r#>A>1t'8Cɸ ̃<%I= Y7V#iOVIPt.`vC郂x?r`]CkA:-O4) B7'K>x\E ]Iݞj_TBAN!ٱ' t() nUb1ւtWݕB n0J,c# ^fF"X5ĔL_kb/-1!+k! y=BqӬhlj8cU_T ΢u>q"Ab).Zàm = RwPްN BTtɬ$e?njvf]L(&AlSJKXk v+PVm ɔ̾+KQ^\d`Khue$EF GeG?/dZI7bO$nv~'8EZ"r e˒2A㑑VřGBIפDTUnX^$dV͏HKKǐ|QUHɈr< +M.'T9FXIb*c dY$ ]~GND~:mH !W_ؼXD;"*y,9%-ONCxeJk:g|7Ue]-qW-_o.s&oo3xl%Af)Jmâ6{:ބ$rIq!(O>,ZHa3Os1/kB%cojOM5[e}u/NΧOL( ImW)ȱN* =3(N(_`Vh7 FVZ;'C4vd( _);%OHc҂̑;sS &/3X|l)D&Bw-&y%jU >uYh%RU97u a A*edF/9QԍHvMAK݃!1SjVic2 NXN!^.H%,*)6*9[,h 憲4~%d (EQHMK0V$!vA+YQ~4NvXŖTflqNuXx3/V/!0Bl3] -Bҳhcj{}EgYjge>ĸv9NkKVx6UTS[˕ +(Cѕ΅ˇo{m=/ʒQH\{Mm2۶)qЦ4(|ԏ+ iG+K 1!\r>8#R bUUG:>~D= eګG;[O+b@eTKDO>;Gt2eULea69M/ PPzͨXD_Y]86=s*kItJT'qrqxpW{n2ۍ, KEP:k { i<Q\׵En!~9 m&fe9nFⶭ4HȚKuƃ-w[)RC.Q2Jʼh 7;[nʉ )>Ay_?JX93EdxV%KF06%"DnkېML :UvpA(0˜/D~d CAP,7)2 l%d?AhelѷY14iAeMp63]2+yzQA!,:udW4*ůRn6"ˇcӈTF;a4 4j4':zirkgf;I̹ T/r46͌B՚E` ! Xٛ8x.|M܋Vby%qѸ>H [C!ꡒ I|Q4Skhi%؛IN"x$F\S{a;@%JC4*gYhH\cۆvci2V Nذo2gʽ@g9ndlTۊZjP'(4|nwd#'2(pP-BX9znp&"ɞE;A@|-R*fG<t^ PGVqbAIQ d8^GRZ7Mfꀚ)͌xi>Oyܻ } )ZX^ȎP)niozP/C1Gj+<5-A#D^!7& \ \4UF37_} QRS¢9d $<옶M "V^ qX[@Z`.>;٦$PQ"a KmNFE0/L%vL"ƆfyR)}$48]3ƾjs`x)<2y?4 pbma!Q;JhHд1h H!q.t!b 栫h](_F֍ɇ\ob~Y͉ÇGCO64J(G biS D?"Z} ^wgjY:|."-ejE0u !D jW{h"κK` F1ˈ4L#+WwÞ[@'^3 A+6&6!y@l<`]C}"L!=g!zdBპchl,V ʥ aC蒕Vc|n&0C2wQ~YfP *Oѽw#M7d#֨ZbrtF Sb͘-SUneT@.i1I+})VSUՈS[T,qBC墧"[6%DMHU}&#ݣ"I[2 &bD֑x9;/QY:|ap04D1HiMR?'?% EoEcTt!tAgg3Š;a\G&!Cc(2Kӂe;Jjc+hd/PVF<[16r!7lPs -6ɱ9>pH'g~!FX%؂ vZ snG [njhXG04W@I ltjB WXƨDh{Pp82S0g}fx-뢅<]7\՟G*QJ|E~ f˨uW2 /҉nXr7c `0!R) ӊaU|4pi{ j8u-K_dcW3鷸m!G8G`=t.!LlA8ж@e7X´%,d}'(m$wif$͡%Ɲ/q\xR#"?V$i@Vux'T|~h"50oGAY4DNjKh#d.z;4 Qf{\нc"##'E WX#V $x^ d\΢Sm<5 g7Z.ui<@y(lCOގ,hݢFccwCv8G ;=`Y uf70QJk&yUQ +iB\ WUiY%hOtQ [xp;ޝ1TcŎ D`pvn`;ՔyHB9 sծITp$&0SքR OZSu+7Zj )2@—+jn5 A̖"cJ"Ts88C&a "%u;nkB[rGK 7@(!#}3ZBQD%I٨j,zDg\ DbXRAg$Jσ&̢{V%¡1DZhhwIrHuLzHZhCsWӜu+,XP\֪'$Y5&iNΘ (x Cvr3EH8f!4"h0Ȧ=*gYr9GiC_6OW)> r76L8=*Qةk!t>?npB+vk%آpg|=UpU+r8w;;jkw=Z%!H)E+D2H>8GwD) 3rni+ɸb/0Nz6LDF!Ӑl6vؔ1MGj5{$) xaHAr> @"B8ڸh`CTQqrʦZ#a^߃ZVdC([pua(5-wVh;cDѝrD ü/vG BjD9BݏߵL,m `[\12u?d ʽ`M+QMFt+oܳ" P4:tDzeOAwW&eۑ-3K* TRC6NeLP{JÁ6Ϋ^PLs^'~[.Hf`~=U=Z= g}jh;gu&vQ\x `(IwFUA2_iXI rG྿M9r?4]w'K~+Sɬ <}~~?3W\*Hf_9SJ! > EiF3PĎ=ꛃS"}++wQOX٣tU /6}K`}j]7F" lѾ"$%j g "PL+B$ IDATV'Xn犥[o*oύI Sa'`Hj_^le̘`MJxk5!"dVe3#9|7:e^GBԛi Ŕ/+z|Рi:7(p L93! E*lpScKz8_ LI&[Iwvno{GLTj ;s.VVVi:tEQ@B۰ew^LD%?.$Q>P]9U)߂–dK[59"46tv-?Q#otٺmUm)Q()m]Rd2: ĽBـDYCه,*tN[Ѵȱ r%P8[\z"gws<. 2=`(Z .?-cS(,s W9PԐ,\PtPiG(+ sءr(@^2nALA&Y8Jī/'č@ "\3>&Z<)60PaN9"1n5"?KC`&r(b@࠙!u(b4ᄑ `~ >_6%gB`$Wh@:d2C>Mw#(1}]`J ٘oO[~c "ү8}٬MϿ?vMzdqT5f|թ흉T|C}g]Z^~/ǘA5kH%0ëStf̱ ;O h|ֆޙɈfK®N^Ֆ\[R[X7`?`]?w}WŅ]Ƭ;7'59uIAο|bޤ_Ho'=̐_Mni ViZsizԙj%85-(E9b3[C(Wnp#W."TRּ[:/p0xZ&:P7|j"'\ !t]&uidbd$28.33w<)OMғ8EY4gI5lBGr9?\V.Jc(W̌Kg8܃KJ|=Zġۈ*|W4<`X҂x|kZ;oÇ_5g|ڻ__:#u&>lNn(0o|Rܣ[SWd9^>s x:Cܴ{^8aX'Cu&?l_ uƖG<<)G\wG4-~G#bܲw]Էg#7}z`,֎Uw_RܸlcrEG:x?OkzsnyemW|ȡwE_0m9}'oUK6 &b(&qGaG*Lz`YqaeE;7uoV}͏Gt-dS c>4~6Z7=K7 \~(ļI jK7 TOk.+_j愝2Hd!zI=y8ܰ2Q$3.e8Z(gєV)C0p09/Ge>P-]cBײ!`Ya)o?Fz/%:pH W/1M@Љ5:i:u$Ƥ(OIx{ .^.ӱkl7#1!@dK)w:oWi}raE^A7!k>B"v2 PEcbɎECpR.ab?Y&VzI\+kdjAP eoG lq?@r过v!/b : [ nV` eSL3OXx'Hbv+'hYhX6N! d*.f0ߧx®aI9H,\aN)?kE7p2H¤gZ[Q|޳3~ǖ2*k9vkJdZ>:e_=۾}ҧGG폇YS֕]^=\^FTW]7M$:kcOrٲ[:}͖Z2빧DE5 \,]1=OUV6y5_dbh紳2x7"pDU]ޫ0ijO[l[L,Y6 ;v^Մ0ۧ\DAqZD~]p@-ڄQ|IgrY ܬ^Mfp$ştI@/Az&mf{pcSԷ(.gi;5t{gkt`ygհ$&,TlGo;AU6);ٜ5d,w hemfco! 8tB^e/ ͵O伉^?___ҞT6wQ8D>ҙ&o#Qsem6IZ?BnTvR)JD&̉^"xbUyrHnT #2I85\) c gj*#%CFW`2#Jh4rU:fp{°n4Yly"n䧍;g;:B%(8Xk*W^F+wlVFyŦ^(u+͂aU X91۠oAl`/I^~q,  %E@f4 3ث.(y2K?(D#0Fg}Zs%_a;AVĚM 蟘+)v Ȕ%wi#[NE-Ud$I&[/e^PeI. ;>! Čf}e a A6 g>d\d6+ GPC^MiYyvN[<,p䷇ߚzAm*Z:SǏޫh]1[ 4@-ؿ =m;8=vHstk?%⹁}yҒ!-vkeWXn@esdKA<x2@eUW+LfL{4?f3S[ #qGDL ,,]M8:J:҉[C5xʪsP2 u'lWQV #-CsQQ_ spK]^mO$K}6Q%Zk=&= F  8pDQZ]}C^f;BbQ%3'NaߣTV=ڙftg..7 +6Ebv뭢fn)F^8 %G^K\ǰ4r95 #uq@b[8Wt,)g3l6#!k08 UW!RgNhYBI)g"a֨Ib "TPx"ʾ 3!j4g \w'-MygkS{K7}YԔm;Pȴ3m*|}@ƭ0)HfS\QA+n92%D/NeSlۡ3m*Sw>̽}Us"FZmv˞m­;:kWNl1pNI ai?|h]sԁ{}y5Nxt\~α >F*ݰy=l­;kW3kvvif=F* m4m}OyS?ZyylS\eip+ * pVF"{hw 7Svuu)`JM!1<$Zȇj% zLmͱ~^7:㢳I^5qb&|0ǵ+-v*I=bF`VO^/䊐9BFcX";%D=GD5yF`a q%+-UkvƾDO"޵Ǵ;{OsgZp݋pD@}t~u:t/Ne5ϽxκWU_=j?s^fwkg׿E+E~˲|k68lP\ů_n~| w-YVm!>gݏ]Z#tJF umB0dDN{Ģ kjHy82@'Tnl؍ cF1?*mQN"2ie9H(9YT!ҡPfr: F=y*tJMgi!D ˘{d *`Ra)R8X{RV\6 -΀izE}-0y2 mcn2{hvd u6$T5K![ƪ;b:u+FJ'' ,{h:TE'YMƈ.iFO%4)'kwޚCJ[h5)KULyS1DbRO SAЊ)K"7ғ^膈R j4%qĢV-2yO* J4q O7OZ  D:^O ZSa/A3T0yV&c`r+v)@cԂ)7H jajflq ;uNf 3uc`uÓkWLAi-ʳtJ"K<ÀSi5@ډԐeܗ`z1RP;M(BAk Y8ukڎK;J xp\3@^Qz1ڙ[.7<Xez(Ea>d~E4_4[q,%?M\dJw~/vv?vEv:41N6P71VyS|!\tT?]m~ {lClx"Ўv"|Ԏ!*0 H1)ًߵjointdh'Tg!eB']2Oy!E|^fAOyᯏ:ea0K*RGfI}E}@*sfBaIa~&eTm:5W!yD eOfRx0r-R?nxT`32DdaլuJ׉wY) 2slD=7Nl"lGT 5{`>cG5%g<& uNڐH|?5- ~I o]9Gp 3{r?NBGքX 3DqQ?~qsEN0c=,YnX\SQT6cm$(Ïl+v=zJv WZSEĊ12^F5%A]vړօt<$makGƘZ4)V3gH3FMᚚg}~o&C 51$)[/E2cn$~'5)_BbA˙ 1G&)f|N?\yCJ5AOʃ'Nmn 9ڳ&obgQy,/0֪%u 8%р$hӏhHNI\ӓEw\8Z>W3$z3,'f=쁜:DUdt}:Ǝ%@zۼw*(+[#ea|8PgiiTwQS7A lǮd2ISlj|p=vc!l*Te*EFe&[JPD8;!dc3⒢ )f6) y zΛŰ{nU?+3>UcLB2#eShU{]\KĢQ5^*.8' +N8Ie$vf\e3QvUG`Teۂ)eImX'+ŘaO))RTZ1e~mFW'?e DޠE/#& Pv{ƿ3^zy+c0L:&s^tӆts QCNœj1Fc~cC2v:tMͥHJ&׮NWz& Nݿ+v]FIc(wu3>ZQAU)sд"@=8Y1D]YҩƮPV,*8FdV2^"$r="2fΉ,JRDfU0wbC}ă+!9d9rx# L-RV1hM*JMYqFbr<"ȴbK7+PPǑ\ڒG&T$H5ffd4-;,hŞk\M?;?ĿXnԌi;?'#2Y,+&O0 #خfw@Uu)&a%N;[a[8%[46Z'J*Y.|: n S/~'F{2Փ\8yA fpujqŜ)2)U[ךQYItNXn5c1&",F#К<"e_je0Uc }M!]n YVt6g#A6}U ̵{0B<ʜN ET@I؁K+ VaB%*J9X9+r:Q 9y)V6fd5ax*jB=P+irVTH8y}/5WU:mT,XA /cQlqp(޲h)!ć~(*@sʗUF<+c =,4(fHpD0U?E<s!q8b9,+I +\:oR+#h B"Ҟg3~  _!p̎Jf %z28/]Gh@[b$k6цVڦ_ORS0gGS\F bM R.uPvr^a"(BLaLXTNX æ+8uh `fy&gQ6s,c`3y&e}|gKUwv G{LIhCSpH]*}D7wkyu~@vGq.FNMVNeA@+>a߬x z¤|P0m R `vxSʬbmxDMa_%Tv.C1/`lK۱[!VP "ZXc\LΥ BCG>abTtx㺻_-|%.c"J4bXVsJV3gsͨc0l wIi1C(ih)Td{>)K1#^`ErrHik\fr4Z7<0T,"F0|D t]"l8SuJ04N L+tz*LH91&`c|Uҫ:'WlL T&FKӓs(آi`@A$@H 2랅;~[YrTYF 떤 vWB{Xt"*zAӤ/|V\"W8 ݔæSB8l ũ.C2ġ%|[ącWJN4Kp JLra nEժc` ϕE4kr V)I6/ra4';COPgn̸8LO%biR3. zRPf啚T ʬiJ}S+;S| = (#/ ncaz"D'E|\Nz-ܐ֊[;2-+z? yvQ1M`bV r~]9zO@ùG9:~F[r Y9fcV$a$-tH9ᴉwjLD-`IJ TBcv$gĐS৷5&Fz >D<7c_Ç(J^fsfTKZ)ou >n^hC4$q_yj7jj%1V^¼A@D\^#[Lcך?#Q8eQqܝ+!cn"w|E@9B~~"ym^)ƀ* _#K5/ Q!{ʱi"Z6duF_L)@* $Y^U(9Ӗh;U,iwӜTvv@ڍ(Ul C2!Ȏ4p'=N ~ߺ}}=D)K3"f~ﭨ& Naedgs37o0(4qB@_(񾿯s?]u٘2z!~K^xz)Ek~w]pߝvO_o'* 8e_˟ɷV]eo}Ŋ<Ao\u"(-#=+eGNUi ö^9=%%*Y+"|[vϛ9rnǟ߆ 7_8OF(`%Z&'Mmӿ|"3"|[vϭx-4G,/=|I*sΕnjש-a_TU ž~(E[t0ƝǩEj*, @l#Z ۷Iޡi8LzYp ZL40D^ !Hh2=D.M@R $;"*,VqҺ.UddiMzE%QU |&̛(a"qP}^êfS iY>VK:kK2Zn߯y*:3^*TylF~-n42 Q4pM$J.Uw᤬Ԝ*6qbh BvFˉq*kHV(6vP@h,5[DdoշEw?GvB_!U{nVXS8kxCUD:M{ ~B&g]g<30̎J꘠`3o(TyY"ǭq'topSR}߾EwiQK6| w v|.3ߙ;kL&Lab՞sk%=_ejFT2R uα];G{bOYoYe'<^DźM>- 0י;kF@[wb66ʹx>=oH@9(3_aNJȆb0#dR {I+4 fLe :Rb '!Ut%5`2֪9Yv һI[S{]ƜYc<&9*f$yXt{ƸRI/R6L>a͘ o%c7*JK6Tوy,& &;QRKNPd%WŅkjQvZ,R_X81'\Mr3g! ["1ZZ;v'` AQg0ۦ)>^SI`5|5!.:}UN ~C5 q7>:~yʯh\,WZvyUj׳6Bz3AB<&̟=W>_kO̟>z_<{yٙOv[\zLJ^v u G[=&~׽k޴mC-?qE'#??v=FY^pwm|˝K_]//^4:k\ p=Z?jCx~}}o~x7?|SYE_v?% }(ˠع3Gׇ_p1DCre7nߴig ۆ菏]!o7,YmƇB__/&~G>߻?p}[_x}oYӃ\{S `_O^s#{0 6Ժ}s/ҘI@@ܖj1\(Fwe& ƔT\ 8,qD8!u'(r2E4e!5XcilejHO/[,aymFf&Vt6cx``Q \*Fѓ>aԮ=QoXRnrVe4afRh$t{lǏNm(Kr5B.8Tch2AlIt +kWS$o()5!?W] ?T+(D͞,Ye+x#,^Wctx=_zkF{n{h ys˶}߻coo~?I~h9.+k?}/5vAFƚZ_aK6[޵G@Sc9qcɷoɵϟ3_c=%OGzOgݱb_GK޶nfju_߳c@\;_z9.?`!]c}oyMoZ{g463.^K/v׸B|?{No~uqi/xCOcV~m?vXtX2!tՆCsKGVY!M'kRx9znPDI340ճ_qԪ_ݵ-K!F舫(j}^1>1CW)Uc!UnIW^g$s[%Q0"E nҰ)QSs/ \>;\9nޞu=uGx"uІ% !Xƶle+o8JJaƺ"8~#-C߻O\3nM{UQt0(bH߳[B/oي>J[nui>ԼzZ~a9lOI"ȕBeBa..w LA&6>>d]6i,Ak ;B8ER tNѐݙ5ĻRvLPAnug Okk1 sz?lq"ߔxGiBt(ӭ 社ɓisd+׋Xoq3l%IG>qzSZfˢFڏSW[[fV'QEM9@jv2"@a.)ZN{й.A`.(!IhAfŚZ(D6h rQzKXTCSbPʓ)YcXrUqYV&ںF!:;!6܅řm!U-{cu[T̀bM:85W$⚟BL.6y~{EIJYt{l0et.بcJxwY=dRԤxf;N 77EeǃDڌu( }SHLT,w$aΌQ\3_U+ӛw@݋ڇ㥇ͽFƛ,[}<{_| pnvZOfwݺIܳKYOQs5BaVR&tF[=ap3cL1[w k}/G|C7[~i;G ]各hNuJ!ܗNa.t;E\ ;Œ X[_ܻXtbx Mt~U~km -H!5DlR!?-kqN^vB7'!ؐ`̫ɂ>$kꔬyМHz*>_™E~BUa}U"'/E4h)=$d5R=Gqt &MPF6|cX1= vJ.6A6AsUO`)&_JNk0&*#ɄU ~j2Y҂ T(V!Ϯ^9/U֕2Σr=q4T}o5A(\Lbf[{V#JJ jG[N:^H0lCo=K].Li9=HWz`AfX8q:IQI(*rdG A8u! *+qeXD$o2A0~0Nx_*E{'n/AM1jSll&hSeF;6S %uTǑ`R5r{N=YfVy OJə,FЅ,ŒӮw#==>6TUZq#|ZqgT'•w>OYO||"P wZM.Cf9m0jn W>DW=raV)6_ ‘VsN'=pnF'z6Z8wii}8u޻Iڣ7lj4M'<2i\?sX዆|;g[8 {<픿xr# Po댷x9 Y|Gy=vK괡(+N@yY&'9! .x R&Q+-"jϲ63g.@'LCJ*CR9M ?oi=׹7U͢~ggSf/}ٗo:D9?ZwvW/o4ʟz?~NF{_3Ez:cM^wL=3o+ Jk_߿} ]{;aid看N;n+7[r쑟~EU"?zwWOy|w>vk]Y.o_iƙ睶ft3,j]/4}u k񒽷}Όۻ,Ub,-48[R!hlSЩ"3/.!6;yl^ፌ|⥟;_}'WM=s=bckkL=ihZeN[z͈} Wus6q@W%r3hB_V_PYt{7Y)`$勁Mѐחq-Mbh"=ç) rbqO!Mf-$>,6VX[U1gulb~2 M@= 9"r7*i+7*J!LD[Ҹ#2ـ) q}ݝ3ɯpqԹN`s#d!XϕH,<Ӌn$}(idqLcFKs(sJ!\G9BXD_oANNKNȤCQM-[($K(ed _H)"CN.jԐCӤUG=KX:s֖#F#>gGq]4?y;q2<%Q.ߝ<TzݱO+xf !5N}lQℎ.ƓW[9=sbNǬz?kq'V-x_sǒ-;E1`G=7>Aa[@8.?A/]m: 9xhE&uPJ&qv )bꍈP0CmXnCL EJ&PoePb`:܋8U)ANJ9F/&N_NZXiW ľ)x]$R> :5S9 @Y:bE69!9ibF"/80!Tk^L0BE0ŕ}F)ؚ[ܬڏ=?Q%;2jM\!n0ErWpMkb-CpY=vD =_$zf'/?{t3~G|ꨇWέeqϻSk#/9eZa!4yZ&%>Ͽc;jcx(WkQ)w=}!+Ú UDF~L&lsff? 5Uhrc6S䩳9)iVmĸ˧l#~C@*b¾JCuDA&ea3nQ"y5M8FQ@5{Evk2[Ue QjцIj<[/"Ud`^jp>&c9:"gE%%\V۝eq[5: 5}6U"X T @YR Vɺ#q{r_ !:ï% 5-6R2Ab5-u9]{lJM#y,%2տJ cXW#tM>݃Kb;\}M}{Fff9:E=՝ ntA{HJlF<K(3/Ko:9s32c5hm IDAT)|]$fnM:s%OUxPZZuc)Q%)e1}L7#Čc uȤ'ջIc0^QYv\Zd@ {b@iTy+dBO*9fEnBJ^DdaT* ,mQkM iV\ȃ=Xkֱ qI֬(q1x#ȁ +Ex5t1oܵ{=XXc>,6 &ay2Enٖ[0JPD t)U;eR%PL` J@O4P`K.qᓨJsF+CWJ琡p㩒ـRzs&"5V%6u\S JC%=ܔY&UNg/w3]HR`f*P u:$$±(Ě$gQl Tz%j.ds3Uʡ@`d"MWr!C׃56Q{g $y4{ i(MTG%NaI^F%!銼jㆅ9x˾S*_u 4DTmxT.da%;Y }`RFf%Y͢(iNj%$qe(,7[bUDʬ[w7In1& 7; )ѕ75z*.ꖰm諙bC`ߕ^Y.fl @a&ЄY8:x#;81Xt{+ 봩5NcezpX4Q+6tdqӈ(r`KO0%JgX(y(F*eM{*Z{M`VG"n+ ;~r((iJdm`v&ulc_LkVV"HQ9(בHJ8A(j -ZH11cr8AtySlcz(lGOKQ+3QV{W$̓t|{9O3CuTRiqs?1]Ob.TV>\ֱ-zigb,A(iHPLL*:xҟ2@GD(5R,HR e$0!MJP BTV Nv.wV$e ܾSkw sSCTcE(8s1ͺ=J*3U]UI9/ QƉ"ea CHlnicX3YY7)7,׌:q%:] Ӽ~o VՃWPNL/1rWQw :8sj&*p x:-3ACE9J3L)e'ZI) )Y "1sEͳRS5&2.6rB,Eghb%@+[mqAIW- f 1I8@DIh(cj -ʗH`rSxP2?ʶ{94~lF)Jq"UiaִFQbL$vuP) `$PT[ t Z:ys]䢺J(\!,MrUaP}K()qMQ %1JޜK޼]LF,Hd~)yQ><ojR)+*v[V0$3p" f*N RYwMq@:i7B- ֩"z}:)yI!@5mPxZ f@ל'$V:!Ĩ& !C_þ9 yF-bՋAE|3C+*Po%'bcL=3F8{FP U?_ y(b){2vN@J tFSF,XC> YɴЙOD:INuYW5+0[m 0.DnBTP=J&mbqMMѰ8T%.7 Pí#0!Axo\j '0mQM"QT+Wm;Zh8)*?:}0㩌+hXWm\[02k}a$)qH%A"0YL֎ٰ"YfnEL@,{ ۃTAM5^ݸI2r"BXSn(-6U*IgYMmEVHf%րZ9f.JvdW$E6$s cf $"@i3 pYJÍ%ug8zi:_ɺ.4Ŕj¨E ƈ)I̛ &Vlщm 2qJ"$פoQa)%_Ym"[|pb/Br Ęݛ4ÕΤA9*(]Z⮧\u3q18>G0 zT),t7s"5ի"mTیc/O:yk)( 5Ehd"v^2QwMD B5e_b [° ـʜ4ޝ/ Q5 }_U MM 5?FX^| S| ` HKV}T *uLEL)*: @(]rG4jei{hN]6_L >]hʱӦ jHR+J'wB&_XIoJwzόUZ JxcQk Y f s܀O_ ]ϵW* 1₂S?9SE|kiIp'ba(, Y[NUmsg^eV +wفM{h{UP6( /UK޶l_u(SL:踃_}OsU K&.{E w4@cRPh;J?by&ՕfXt0"=gZe+ IP U}h yƕZ|埽7߿?$E[ݕ&E}+>ẃ{o}H]<+(0.$&'Ɛ(PY]fuTY0׹3fR*v>x==x֭-R5M/٫úM1986cc|0ss^}ؾgndDf$L"M0~\bY" P˞_=HP6[TvYA5*n(w/;N DalqK]KZW-IjN۱6~gv?|"~n5ݺȖgϔo"&("&.KT!d$Eŗ!~9G.Ͼ $^(N[T+C΀2yףYdubR~L{;}N|XIP{-h`M/a zn Y4U]~A D&Q:ؓOS*]Tz]mh5fm {;~3O|mkJ%q2P9&Tebp 0!4׹yǫ4'S[>#9g~~1oιw''.L  <__Ν1s>ݷֵg[@ nQK쬉 /Nf\֟Ȕ#v~yCZ:9dgVP`W53 @x3hD{0}~"I82&Eiq4 r:=8#[ev6]PvW8U$&/2#gl/m;Z?5 P ̳((j1>< F$W_O璿/Y,1"gN^vke ޚS㔜ae𙓖]c 0A>ȫiȚ2EdF˞=PnouӁ8n'Jh06GFc| W+s8q-\#Uó64k/2H8$e>:c%@#0DzM61=@:6AUgwA݊'2J-L2 iU)rpmh1LV?TC,BnWkYfԉRu:fĻQjWK%)/E"=q(yъgzùgLN؈F(ҬzC3c"12;#yx9I1jN@?(<2@i!oϛ5 x+G* uyD!lɄ'3X}F=qS$;vݶ& | ';vxDKO2S&aZbcSd"*z! lObH ѳO`؛ [kf *n b`4wEH=b$NQN-:l bўG%*޷fͷ_zOMF5*1DxQL0KT@rkV& 7C}#n$lܪhVDmInJ#JH s`V߮Vαm}q}S)4%!b%&( ,{)cRفnW*fXmRݍjL b:]1Ʋ#PV{O!>q$§ g}Ε%nAUNWJԺq<ξ%HB{|9_M3 h*eS(S:2m3AN[:c|~?Ow,~sv(Mog~F~{f1v"!~f)#!cT7 k0`֎w1fBd5E1=rxu>u LZ2y`ȉŤ:Z_ Q. G=)~<0k]~ dY]o9 k?csNe[}Ue߾t=)(fĺk_e\ zMh3[~;;$+5dMWX(<BCskXk{}o@_we+"׫[t$?q[aJDY5]=a;yɀqյʊxͥ_oĻ )hgm? pԨL=pէ~j!T/ëͫy3?]ۊ(V#V&]Ѕ-o5XC`ټ7k0iC{ !eC7ܝS/ZU [b's}3'>F=7x罟Lziى1O+1ʘU FM+/d&+;LKCfj^Rt時O2%ꣻw4NGxSK)QyzR=>?Tz`R|u{tf g*ѼDoke]jf{66xnȋ'5xbVFMtO\ԪBLsiq6##>\nW?T~G&P K7ׄgNƓyV@VkMk7<hO?b.2߅{pj%̵GӫC{.dqR٧a_kZRd:8:O:HSOG6sY#4sMۻƻ5!+Iy-G}e}A(2dV/iar-0T[{=uU#>=gRӘcH"kա{V>TZaY}!AzOㇶ"=1&;zDQΪ,Hqi ~^uG/gd%97t#2vZsol$rD粹!I IDAT* L6FmB_i ^-m;_vjhAU;;߾s àwMxmUy+q;˹ NwL9iuXV/r_@HaЄ^襌$GEAI8|1k5 Kf':=X1E#:/"dG" ѽ]}k3(|şyfޡ22\sd!N)h||cUc:|U'n8iuXV+rUt19;9aX+7~e 3k}zwxOV |解3Ίf>pb߿#\M̸!%O(2-&mjk F[mq ֠l_' qdJ< In~tn?j>T򻟼k9n֩nHxVד4EpphCs+*pz-s#1'2\OrJCedM3~{n{U !F*&"FS =*=~ΘwSWL(׷v|NdRPSxFoS[Āoה5<5u&^~֣gQ'n8/|fc?keS+ Z Kv3&D+ [pݟkɮny6O>ϒl`,+ڼlG?-uvV'y^wV~iՔƮ,JH.v,+&;i B%W|ߊ'1S'bΤkͩc{NMl`p \Vļ!7S)翨є`@B|1cθmϮєUS?:{8O7kq}_@gd&zp3*xZd%0mo`2FKS٠ 6&4tp6]_:y/ޯR2Ϯf~աڴ~-a{:O6aO|ʶWeԡwvhgt??^}tVN9VyIFQfhZ=c?=P^xnQ֍Q׽WMnmS+ {؆s;-ɞΘ MIEK-+w\w(ᘂ?:TR0:_9Opw3sS]wJ,z E5tGf &#s}YnSNW*{}}Iջ݄:;>k>͸Gh-^@U[Z=>qgWiDǯ;h⥿}?X}Ry[Z7~)mGf8#}]I֓Y $OC%L+󺞼dDw[/$ 1I=B-(O?ډ`]V=C-,|78CZUm^Hݸtv͜i1iO".0f0c֣V0 kG6n?cJ4XB4Ʀ:.' Kl-?My⻫e9]3 #̜cF4-:϶%EGfV/s_ozq!>qCz :=3q[mvSoLv VN Dn߿jvZw.~f!)G3ښzb1@]WjX%?Uzש8%7ɹ򡟈~_v/0XÐo283_9'럙w_ 1 9@}bևu3h˧tXA>+`72K3]s/m=9jņE_@}B˻]Y<]c/t$isȥ F#.v$Ea sgÌC涿|.1ƯYSN>u~zcz%kfŭj?;NeĻy*U7͝x%*lN㦣y+̟x)9Wh3 */[ȢJյa,j3_lv<ӧ9yR})ySPVt;{k8 άUz׈N؅O6L+iJױhB7 hh0r0\~ua7xU,kmÚ=M 6awMSsOΣ|׸T:+)~B%W ?t&mgu&b3^tx^۔`cTFq PNCCf(_AH =Zmg6+Hw!il*fb먽2AK18q"C><3F=50v> m}>4jzIKJ|f|WFn\NB[m mq[g4UU;j~BG$c>)lpR򆣹 Cu857}ஙv5ad4[cu1I~>³ +N`҅R⼗ca2bay״JmXgDmSͭu2{ߙ;?Mmv3n)^ܜ;0O%f caN2u['?{SIuFM85rG ð2L9}PX8GBxÉ 'hu{N%{L`oFQ7jw[pm?ᓝE'>Ut㘆]%<`N|^-.]W hw[{:bt /oEUIjrhvԦ&ڠEs V2k~sI&]%on._2j_}W,a~1,~.`es/{Ѩ XuݱL3٧egd˪ͧsiuy g$ڠ쿺CE[Nt+^}~xөnaG]luȇ]|c7h;z[,V@R!8t9m a^}xa)1}w\GBWBlay 6>P~u6x{1mNӑ[FMH}1>Y>j񱭪lɧim{6'7aDa͡QmI=^eDFn(T=5/e^H 8P].c@3O2u8 prhruB rjsƍ;\JC!uSu|mN^è <% ?͡QV٣3;)Dʰeθ$SIe|3s2֨ x0׸FX?1)9-]`Ұ'j)FbZX-c/||cu~1/ءY` -v{K*lHYtwNY}xNn'˧5$[|l?U C6V 6=4)PaJtpKl~\x B*LC\PU+Xoxd~՜~Ш›+sY0/X:ꝇw]bKޓK'z'>U@{Am@H )b( bL,ͯ `jlmѼ\5c |G'yb U)OᆼXPBk@PU)ik k:b `C_Mys~1b3'@ 70B  1U\Sq Wg@I1~*|ID:ЈT7:f[ Vնo/yWm 3 s{Bn= ϯBAa8Sz?8D~ Ja`5h!6  #m_;cJoI0nBݠV2ؾV99 IB_9bkWT0J&y9_z|A 9!'BXQXj[{L1}̫W\V_~݇v]g]hɌn~x)bb7,HoZY|Y=N豚]p }qJ f(%5*|G*R^-$_ kmKԪ_dS,LSmV?Fhqya^}:&sSNQ`6)ؿkU怰L[\T`pi FwqS!k/O"};v ̥zc :ou}NvD}4ֳlU)+ޚo#\ 3*(5_}GA1}AQ3`$fV:ۚxҟmjաON3͝NJA'Y|*ߖ^s}ezh[ܡX)Yya BM}_stNDshT-5p^Ihν-} Ͽ),f;dVVJ7- 0o{E""MhƞIblRc=e93;o>k?r)PMޒClfC`Г!@mU%~9aFTJ&=2p:8BJvl!E,\`EJn2A`jûT B=ЪR>BJzd}o][۔0ԫ9`c[hƬUx̳cf0F4CjY vSRxfWM~"[n>5O3Ԙa]G=}kei^'M"#*[0wȴz5+9`k\PG\괛h*gbo=Z: {Mb e"A"Oza,*<Ethgq-O/iS}(9`XOc]xso.ey&aWOƩ9@-Y5YvE09(1!ц! _Rzy=qgۇ/f7E[_ +jΖB#[a]̫.˶@B4o1o;cZUN#?,d)P4,N׏~:S 6iLɶV+Zv݉ҬnhwD`\02 Ur_Ssfu#N٭tM<  F Î #@\n#$H4NfPYfw~˃XIf7th3D1VkT` Ơo8]͵ C8I , (.h]E1ƠV/\(#޳g;LpÁ$~\Azoioķs;zkN~2r@36 E)]ƿK jEXO`AlӶ* F6Ad@o ayş?ۖ0of͐Җ7"C$pH~!ъ@@_Y;3ѵI ^YKՋQ᠀PL3TYNG*vY_ewf 0 w&ئv~{M%6bD&do:"Lp M?e@0^Z7m<)QˠVq\ƃs$XbPܱ"3 (:$?NV [cT# )Ko6Gd~T}"MSj)ni%-`h;Wb3L-6s{)Da0ٕ@1ZlcVO3~x{[_}&l^T!YX`Q YowjHiJ= due{n3z\ {>ŽM*j07B|뒘ǥ 9).vD*bn*{ƅY=apf|a{[wN*j>`-]ו/xaAZwzI3B7eDJe3[z8p5,=n]/I㉄1F F of2 zYx>痀O~CvV-K~%7եSY )So6FdūAcHԠ GOfE;j$奸a2,]O% VInuc0Tv!;khx57i4(!̓.00YMo´Ӹ =n}eݫRJoT5!`?0PٻfSVeTl U`8aeVE=~W =mUCݧR:КH IDATW;UET(.rWQLn t(!.JwTKS úzDO;yx_=ͣ{ssɼ^1Mb%.hٽ!+2:Lvc0ݯquxu5Ivvr~w@]MMW;jZTYy^>R$RQtN"o*]rĐ^€ TӸ5r:z}-IvR^w@Scb>NtTa:ެ T+F4vHc@j##Bҳ,9DD"]u{uKrh9 Mx &]0mI4Cn Q:>6O6$suACCC0e:ZVniǴ;a"ݳluAՈn~قaE{e+ЪLN=D+lݧpNcK7niwCjͤ/L}{hdTpz{DWA<H8 0 ZA'hIM]v³@X2I hŬH}{pdΧŻ%޹nݧ?ףnLut _k1F})lr 57nh넡[k ,$0i2GMl\Cyn=H+zs#"(!ۯYhA'o96t3+={lԪ_ist[{<3 Gt:_ R|.Iuk?AJ[;17ŕzjaqJOն;Ǽx`~UK?6dǣmL0ǭZT)&Q%>WPnaWu}\=}ƙI#G=n/ SsןpdhP\]5240@y~ɗX&щ(m @0y4w\0“ qf&p3j%Pڜ5z: j?$/3Ƀ vnFYcN+K/DtrbTےOb/J697edO=i7n݌wv酕I:톹 ֘$T?qկs0$bPlD\e|a9gRSGvC@,kKd[]i0.ɗXy~^ݧYKOrbW=glݳjUJq<̧7%I>4Iwf΢\zzqN4=VJK_^USoN7&LbռO3P>7 +6s'։bCAP,mMqe[n>:eD;#<~xǒkO%+F?Κ( jM+qzlIûl_MJX !4a*,e5U%˭q*ӋڬW]vh~{`Fܲ&NI3r<é({򡶚LKׯ@g%xn&+,j=ƷsŌPWfuOͮγ:ݙ C;{Z^eXn?ytcskZ=^mm[a=>o>T0MHI&]^sV*%m¹y`VWqFx2m=^S=aB]$^J3lOZS;̾.@He6$O̪Ne.?ٙdˈ"rBJOJ(CW4%f90ԐOȠE<㞉f伶{'s!mzis\Yq'fTN()Z[Z0>+c5J2tPC 0Nf>yݑd{VїR"Ӌ_p˂x/Z< %fїL?jOfuYQRtr:&Of)ї直<""A%` {t3FXYΧ?8iX+_m)H0_Y{LNd†툗@40BAjg$1VM5?6b7^Zs//lHC0tFQ8|Pef˵:Oppr~ cPQ)ibXPU869׫?bXj}਺3;܃[I!?bj:tEq"nfKfpbxXyU5)1͋gV=4+.wMg%8g|wE ,c0^ҢPh:gt47H+C3l Fmf/a_0zǘW9t5n/e&V*ENMsnKwVev˧]:5.E≔B sٿ cVAc0TSeVYcE+;e?S^*Oj5^oqxwj[Qf2 F8vX{iq֎., `3<'..s):cۮۨh`,[[kK-i' cசO6Tjag$z:즕ۋVl.iA2a%sN6sB*%7Ҝ:uf13 #ٌ1;&n[jpcg7;hl⨑05XT%c _X9w Jkk&|!),0׍87<ƅii^G"#\pnAh}7.P5^ˡ|jW*j[Q#:_?*̺ÞA0o3= 1R[) >&)Lt[? p4~؟0W=Gë[k8*% tPK_JvUeߟi{':-vѾS+!&g˰|_i[8 AM]1ה60j겄Ӑf'@US^*(CO~6߯z }^#>2Nͩ~*Ow}{MS?,x a} NF4|?Sݦk[O\N d}pnsQϗ]ڪD B𷛫nHMSZ_fدׄwNhȩa཭E Nd$:kMSAcyu ufm16JY;4ťS[zLoLhX5pt7;Ggzhip͡4F FE'hU5$ՙ^Kx޳.ľ2sDsucTUCʒg{-aFS>{׵#A_WlVOkqd8 W4ԇwԫCe~xʰV`b_@uqq_E3pSeFaSu)uqf%(K">OhɼchfE8x}Gn•2<<Pqn8?(a]M )z +# 8#o8ќSAQәb {dާV34SM[;LJ*6ᅹw?ѧhx1{:d׫C-u&E#]>탳*άD7b9XL` h |c/Z>_FiZd2@' R{z3FO"P`ё.N`1)%x" $@/S_^ ;|o$#֪iJ';{Ôi8ㅛl[Btl\P0뵣딈F[1w˅v޸?#0_14yG<7Ze`^y+xsO`WJ3]X ׌kAiv#6bpƞؙSO0Cԫ?_ʢ_d&iKeK~Y{eB2ʽnڟnwV+|@I ^_*X"Oʇfćb#PQzGa8yC޿@uP3.>hC,ܞ dGȥ*Θ :\:c`  Tcr1QUD: ?/"H"W D~A+堮%@NHI7IѾ A nC+pg,=oD8!)Č !]#HH7..1U7iLxi$)_y% ɿBy *..6#V@Kx&#vp%#X#Jw$NPwÐ%颃#CHB.v ?%OQe ?Ib$ s8dd"*z dJ 9t L#HH Iwy[0)(ET@ m" )lHV`+p^͵퉯n"ծ(DsR툇EpQ%9/O;1ҟ?gOhR@o+BXI1j)p+: 4otGAF,kB+\w,Г+8QVVC_zɟ˱ H.Gp:Q7REI?_rf`AZк3֗~Qp0߷`8f҃ĘQ|f#Y 8%ο핵;nV.I",ob- Q8G" 4X mHr#wIH,۷鉟3Qڝ޺a$' ׼CB8 d%A\%Qw79ƿuѐw}2DL!.J&QTJ*^pUT f䐞-gr{~\l$6XӬaA(F1M34-A ͛&P@'qEjJoӲ}liwvK+q4ƤH#m.EQ1uD^S!(0H%W7rT6/ső4'(F&$?Ţn(Hm~fefbt4h^{QP4nxs|n g# caJ, P#zL dLƙnT0VZ#(HS-]2--*8(ÑUaE[[#ӃMɍ晈w|jBE;(ĒQO!ёOސ6Ff!,'x5/מ H+{Y~ INRnMcRI@$@!QGvW7Mbdv"?GMXHWF8Ɇ+rd(V!BBf0CzlM dӲIA$7d A .K[ -=1$8E&,"@Qn6(cքuUK>SBR*ZB^n`AZlK>?]j}q4~3Wn d i`@ę n2sŗ`XcQʚWϚ8B1xDBg۽~!_:贗C49 DT-6&ݕ t 33edf"#%&qƑAsX·? %u# bD1|d!AQ`gϸ1_z.`&#2(w0 1XFJ*sA 2/ͧu0GƯ<@M$"(cP0"Wθqut1 PE@z-h(Lw_d6=D! Aw0дSU q A˥=.D*``%c]"XGvDHqX.5|5j+/Rs$Lny$Q3I7^s"$)xa'8)ĎgުrHaɼ LS 1WTE4JzuX@@<8$3Ze+H#y$A̦b+E a%``d0ӘfdR!@pD* G\k-GdrS!4j莓$z!?.jDZ mTՒ D"d]a&]`@H z~8cwF}{d;LSݱE 'Td# "#1hDfmw/R)D/0m v2P:@v#21`~iJd?e5c!ŏ ]e1!{WR9E$h@Dɿ3GY1I Tj8興0OL/—d~Kw"!1<b-}=q$1IGdAIrkI*TS# *x#I y(]׀"cObbB0} IKd8%E/.[Pd_"aD"8hDήh3\h"# $Bւ)x2@ϐ䀐3D ex@Q,cEKrY#@)UV"0l41lV6.Sp 9 =E9(ENQ2O;A^]vD0 G(KaJ) 2k/NěWm$&?`>BH8@rGcDIαG3IQ C+TAb0yZ}%<H" É"Y">?jZH5̧^ [b]F0M62[ŢSQZ`:$#K\xtP ̠""J4`0ƀ0Aa"!`?&R#&C>]c{V|B2c M` 6uA1$тHJ`gԹ ⅘T+j88-j6 l0E0,$x}un=ɛQd%1``evA4Pp<!s a?"F%Pd}aX\nSjV&0101Q#I#9#mia CDД88s keHGCI(xJ$X B.8 V2IGJ"5"On'+Ax 8+Bʜ*iS&Q},3@B.LRd=ci F!鐢.P+2'ÚHP %Mt*Q+|]&r3hEnTAg+AXڞX8'x/"v-"BDTWhUPq("m$X's1`ᳳ\&f7D ĵ2'"WL4Le Ix|6\ Zb A{אlY^i2D!7Du2*3dQ"._g-/|C m8D|9Ndaɤ K"a5D@J/_iCB'1?G%/Oޝɫ$LfI{AQ82jzZ"_ZX[Dr8QA J*\z<22͔OB2 N 6݅8zEr(DXZX9%[W2җ[DA1K,G6 e5Aɱ+pd۶eQ'W_pd@,A:/DE F"{-!j$D2sQ k <,e bׯ\8'O\țCY&DlˡLa5VƼoْ4F H++^/%!PB-@CQHafDE GT! Dj !˽g}]{3˹krα+-O!~ڗN"Ew#>NE FTGBM Ku{N<{ r桅- }B7X ]bm*T0ut^0)XF(qmT6m` 6Pz:m,ʆ  "VGp8";>K U.?w dDn0(d E8*Q7Q\L\QbbipE;'wVY|J_H :&H% Ree/;,<iuw#cÀNPvEI >/ wD'&,F30BkCL\Ȗj3qR.Fwv[+"dO@*#ymPz}3ֶ:1O! 2sJFʮfNf$le:[5N"e_՞+I`3eB4Ɏ;*dg 瘺0;R6iv-iJ/k9#B6 TJiacX)Ȇ /SFLd&z1Dp ];49Vkr0r!.gé5dB`L+k>[v9H73shх}Hjt.J\:XTB*ҭu&6Gc+|zEϧGpcCC?zea;>tE/?'6=Go2g'jT/`plZ{/P)51ZKB ݐɈFɤ}_0mj[y _*} O\z~;ݲX*#7V@~5ֻۤ?{/j'{;}ͭ?s>㺳Y5ÄށZ(,pΕ{]4*zy[a]d!v# ՙB'3ABJp~vTf\ˏ~ }?tyd5ڳ?/d"cCLd C˓\M6^jr2(vLkwtk(@ ϚzֽWnK[H,ۖ\23>JH10pU@}zj񀪣>Xxd9MʸhqdGp2\i`T&!s/Ϩ4:'0(`haxwQu '`e'>Z'Qܴ:u9VFymcmlIT%,/gLEmf`<ː~DΔqspդ9‡X6:u·Ж IHU\D/O#xn]T 2Q4_h _3?A{Wg ݗ߱!NYBwEO7S+ߏB,pBK;48NOڎ\ u~lr-[Ȇl)9aH#BqL/rP [Ɵsʼ*qd8Yb#zH4SgS oQ k*Z玶2n "1{,e JAg)#G8/-m2WpW/rтݟw;z*,-8C8C;(Q9.4B'u!JO.@G\Cૺp&O Q [yd 7%B{rV= z тþ= R.\DK%,( 4G KV38fiu`]?=~U/<j(J:_̶y/$o{+oedNe9OM[Oεk8B"l8Ol OxcN׵_UV ?ִG~uષf?= /TU zi&vk1 Յ޳|s7ⁿ:zWQ6~rŜmb՛tZ {o&X l*tQGoK!غ_|EGl.Ϗ8y+=uտ~>|h@ryikg6v ^{w7S'tRyw>{PP\r͓kޛ#G_)P&Cg|]]W?b3'w3o[m~뮣OIYXRfNsֱuU0;M~޻x#. op}G=z֜魷}i^+[>[>8Ɵ=| -Dk_f8os̯?l7C-z7LAKݽKC=O]Goigje'qMH3 e %< {N<\SLuF)]Յ(4zSu-Mc 4O;z( Ԟ?]wݧV|n|o{`s<Ȋf2tQ~MkI<3($E5 Εv` Gƽ$σDuq_bda.-Y.R^jS8`bi9K 8?kǚ7;*A7V 2b&\9*T8'F%)o2 "Q8$IW[BQ,[$203G_# @gy&:'YF"-.$GA1e}v|O2<6u4Q QuW#Q6B?ӎ|)R[9]t;w:?}㷧K@2ѥNZy}'}Sͩl6]돇=z]7]Bx=GoYliZci 6?rM;gMڼ!kˮʡpÖqv6xuxeqVpqv6hOLpo\u^{t|,]ۣKS!MU}eo.`>M_Uhv ]`ۿ-.)-sflnj9{gM|%\Z~xG~q5OpEHWǽyǮz{%GD~|]_} ^I @Ug>7}n<|ߦ]fH'nOM//S\cVzu ]?>"?k{~q;5[?>\ʰE>3?^п,|^|)tW yG̞yO%LΓ^'[\~˄K~j魛mc>3&+ܳt n7ٓ;)yٯѷu+n\o/]^_3xPg|Pwז^{+o=X01pL~M –nC>rVItB£ZAN^O|r3gPS?ba h-Qz( ׽ßY!k8Ɖ3b@|{PL0:Vє1"bJ%Ҙa(FǙ|Hfb\Yk~j^1EPzRE֠ddqG*L"(şM2Z\XF7.k I]4qs/+9[1)c'QMM1 'Ok31]vUڍ{,]oyiݞ;`Goj̤׫sJ%lyinMPGu7L osF|ۧd]V9嗏7R{^x͔q\w3^|c3~}E'mKGDګ_9w/=d{kqM۷xỿ~W'V̞:뒓߻tn{w%,_7f{k2e\ogOŧOpW[;cWߙĊR^3-T]9SYf@lQy_jgvA?7Z o%$# Ǚ*@(QGOŎAB=b)G jwwo'{1ғݻt|+fJ^-\]9 '@㘾 ߻C_gpĮKN\ҹ M}ڻ筜vȶ5=-a[ݜ37h7&KRfW{KQ{oŎjfR iY& IDAT+Yͤ1}~WO؊={N}IY:7w&=bv\¦꿾>kں lyRQlp( =胚ξ 'j٫.˲|>evЩhUjߗbQ2!y "@"h>5AMTm/|?b};NeG`fNϰrltm^ <[w.s2En.r.I UvϓH9Tu6,W.tsh\ʟN;qޓM~&#b"Mc4ZZ`(݌8%f7$q͆8Gsn;>On9Á,#z!C8૘,~쀤e7s#yDYН6 z|z[K`118DEvU"@.QkhX- E("h2? b{r5Zj SOc+fקK6몳_r$ooXHNl-3]yBeEq$VSOZf ]_<{Ɗ\}`Ǽ\78M4o`88˻z WO]qBCBrWf@^S7nQ #I"Z$OС7l_'1 gÙ(33z Ǚ7[4A.|vLsDV euGF#99 f ""&e0b'L,[N^y/]>iLT`lL=ĀcQ<;z5U fYfLbYoNv "OLє9 HǬd%W9T Jq" RqVri Ǐ, J1RM>5=Q~" ۤ Ip/;+; d(5PM>&o; 2uHf3.9:f]M.9h&n2d5Zq Zr #Z|lxʀ 8,".@nKX^b+Q&SuE֘ƎZm'=9tS ?9\q!^ߠW0x*@:`eQ]1 xASg`17gnsk=r5|/>))wU5Nضgζ1[kKފފ#nQ;[ G?]hiɗ2qB漥ԶBN%[{Mi*FUuՃjﹹk_*ELin={JGe;{rP1QYZ3sRᶷxtp"J]ܙ-~ڍK%g&t%4hj,%r X3)6Ve*CP.%V?7?asrkWaGkI[k6m]nb)Į# 9Ns^T!(@[WeQZo}-Jl}м=&ĥ(-MإZі]u3 r7B1@>C`SkUPyy3mU)aphobScUCQI5i#\XfϾeӾ Fмo//D- 2ƞ]BqrdƁ02NxcG@\0iF*/uyM> WWpLeS/C6OѴO(~b"L'}q!" uı#SܾX1*'O0&wXn fef, Te6*"K04DpLm``Z5P˰.E-~|IK̒ _##7ۇaN0 ge$fL'JD}nDI|1egTʌ*ꥵ/ V2 { 1DI3P?lO6W?ʜvf&!(BWuWovԆ8S1x[/9yC.SZ0;+mpގ9΃Aշ."NV:r}x;Zks-'yY_;okp`sygIczPl,@g_=Ks;_{Mmy.9yN4N8}ᛴb`sGⴵg8}c/」*rncvofƎꎾ%Ks_Īhq/>i}.K"I!uD@C nsJI_=wy;z{ew{id3Z}wLo; n quE/&Y9#766`姭}{lvg$hN_}Mz;^9M },جyXh/>yq3ֽf^),|ْ蠽fjjVGۙiElj 7l)s8uS;f6vzKNސR1D]e[: 'eY:~ުHZDO=^:|]{Om![ej>k76h6^P_3 Ϊ?/N[{ƑN]N㑗f_K-)# SG+7vtU f[:2tg3ȔͶQNn, wG0Ω0Bdۻqq6sg 1,4f)I7f3 mvF 5;Te+JWj,I_v65_`V,7n[zpv1\a FG\NPej3T ,P*P<8WƚTÕ{AFoMf/s4bj9AGj"вym] kC20UGgQj7-f=pݥz5$bZ r鿼1HIJw(G!bTXY@ ۟88e\ֺ?w.'}pw./mtT^r+.ZH75]'e[p[S745Kb3'uoxq7ҞTU1?xؾ^R |qߛ8Xž;yirss|zތI]I|og{j{e~xkSk3ۜz3_GM]Ɇ4DLĄ>rHw>k{K='*QHKLo}ߕJџ}G "Ës:z qkW:Fig`p!ʍ.][~]"^oݲ+D-u?zU09۟\KLiپ_Dz/={[Q W.7?G^OZsϳ~ARDY^21/Šx<}i9[_:oe^M/2ԍxI*y-TU K%ňOW oiYtؖ0"wM.i[}ba( &/#𙗗mݕKh/+n9髟Xe2֖ڛ_Jܷ^KMe2Cʯ>Ŀshkeo8cn}u1{{K]νK%CMd(!{|=w&,e@^rm_:At zyKA;cX1?E6E$@]&L,%< y͇m{Roga==qC~5|6K p-W#Rr0B2Ѩ Qn{Lb9}Ðvס # #<M-)у(ej#eE~t8[x@Y ^cj%nFHCyK\Q٣}QZG5¡esIu4 8'^F5}yT9as}[@ nbj^j1W#|W9s{fSyBPJN%lS>dH uç[ f2>PSKtX\QG\tݏ^m(JIB uQb=` ;N3A8$0T `B%jqO0SԞv'>hM䇖4[NQ4EzBJk!1.4$XQPL#?oMݱ>uC3alme.KR$X9E7-j@Sʢq7VI?AVZ2왬˔02L,H$9Ǽvٺ6y/NH`h59"ǮFdah>fS^QDaҥZEb,*dp⯽dLQ4{n|Ntxǹٲk/iGVp2 DŞ2s,-!^Y@%@u>8MSZ&N{KI&=2C ɑʘ4)d@Ddݓ^Ks>"OZ:.'aWlSZN^MDe[!'޸ ѥ?Zp>ā ܻ;7C&WK39V~u~<vwT~{+%b6y^ֶ3?5|ث[W#3gQe`G)>i5fc5,1aO|wq>[m 3;qmIHxsuol<绋+rE7C* 1Nt #6]{1]}fBJ{X8VfN ҂,Hg^FIQ\QJiy'De%qrjl|fBZ^a2F(}@ATĐ+0=XK<;j$؝ davjr+bDɠ*py>SQ5q /苽lW-#Fۀ 2\Jit;! " o@4 Rpqe;mjĄm&R4 $e c&zNd+6m-YBi'z?$ KqfKӘtꂎD'I\gU}}ȇ׌F u's)R5ze!vK+| tAi9KqG=Cڏc[j%Tt*C#fH?ynx |UJ趖hzE_;[gB1b24ҋ 5 DHֳe(#I w@Tr5k_5'|%(Og䊢~YUQ;(Lbxz_wlZ0MmRd,!LkQ%ǟH\ T\;('8݆N8LAD OrB9;(e# e#H^,AF^TJy2`l}X\]2}^j QIVmxH $ܻƛ{jI7v"!5% " m6"XP1C0b-YGIO=hMp!yn`QL2E.s=E70=>cAqk) xFg(@kRsJΊ]3qAXgZ 9V@c ["GF bW0o%$b<$r Fg찹Ň0qP7rFaᄴ*3!21ɫQ4[L1nIYQf(Yj\ fsutI0ˠs@R>\:Y@za.(_<2']dxb2IT;e߈%V+ ?PEn7n@ IDAT[jzUksm" ;Vq1[flGcRƅ2Q1bi7AA+ b6 K _*M6?05eI0.S!ܑ̜6ٴDΆ&3)T1 fE|wX^ݼϮ8]NGh09Q$b ӝLt⮑sD{YǯGkΠ(W"5K-kI$юp=+<ʬf*؁܅AXCSSfnO*iyOȓqkև'6kaM nOĺd t:dw,8:Jy &Ƿ4vHː#3k$Fo 6H>)-dX#@c1A cz:d5InFrc!K5YPhQ x~>!o`T>tK pρHeob24?wPSH׎BH;2a\6bDFމht{=c~G \ qg- e.þEZ+q _'! M3yM'uG.$^""@}U!pHi@]hɴD_yܦX-2zQo&9ҩl/F {RĈlg'VH"W/\3^Qh<x&-Dd0IW%֖fjyHN+Ha:jBaK!Fz`p\C8'Uo~M`fh Ւa2 (?B] [C,鴍AfHA׎2qnqP4DqJǘo^.b$JΔE>T8(k=%U69a}"" 44am)GW/G,У1 Wdr $6ƙKӔ]@{fMEÞNk㯃̇ #5IJ((q$#,TN+(g"\0ԟr!0&QD&| 4BTPKצwfPS* 43_/x8u 9<~縞bԔ=RqC M-;AIH C@fT޾<ܯhE`Q0ʮ9<9 ME@HŘJd+Nk >bƘA5J.^3nf+NF+%ϳlp5f̂>a T#Vq ji#$Xx@C@㇐`UrXJ %. ƥ"ű!;Iy>Y`R*]04uDmjT@3"Q4"*AaF.O|hC`gD(`Y{t~Bο f}#XNDÛf8%_ eMa9wB"Ytg*sǖP,H 8G Gaf/y͕ƜBγ)DŽJa#bu*ܞl,g8;g Ӊ΃Y.)""_8/bTh!f,FFxo1!dp1c9XaȲ2uGdo3ʸakI:߇r-}1CqҮt4D^Cd\C}8s:MDҔQlroJЊᖷ> 4A]j#0"RLC48@CCT*jl `OF,w}oGNW0gڤ+fzD))c  y7 %:^QpR_0uXP\:I|PxP/'UktF|*y$ Ya4j_"l⬪%4j>AkH"! Z'c8381Z(>:EfL!社ۀNmэrʎ{ ]vHb pAzuaNHkתeT4aod4>Fmgʹ 0C/`Yl4zT:\Q,`-'– );"6ҋ:Iب]ɭ(Q)59Bur%JdA ,P1 /Jt!^gwsjYM0X){]0叠 *G|A k DL%Ԝ%q|UUrA51! J)7Wu9r.Dq7س[ >z6b|^(3䶨'B xW9u[3^i%șNJS, ֱ~#>lvp%[SO.e6Njވ,f9EP3#A9;OC5'@p/F)릶NQKOǥ4־}|P01~6Zs{z Zo}BYGǁЅUw l{#:Q YjxL_FꈋL ZB-QeJX.0Ct)͝aи|9osbD(p{ [$lDN^X+9  %?B&FU2QLT*AHa㰧 M4]S(bvѯaq;ŎB(_z30qI+zF($>1`/=PAzޱ ib$%e#K}ty yN~(%~_0oO(e$q a}B,f$xvȇMbi"]}_{Wз8N,^NVGcf*al}ed'^-%E%;z /M ]Ӥ-,!o_#{ 6ْEkTJcoWe_R|&!V!BwE@7S!#9FG qg89Y8k$\^51L 9_OsF.l紐9ٿi"b8\ܾ€S‹u02LFUd+]2b6ңR6H0i4Oh2DC!?L0߳ 0̀8$ҟ V,]f' fM#gMg:)gUF}וFG|gv[TP=RIeašd"EEșD8vu:Zxq1 ٬YBh- 3]J(ھ>-2c>'GeL]?/?O7#ltG O̭4>qeJ{SVފG^>Ǐ/`v]U|oLнuwgyCBo< &wNDzd^7x{w% dlrvV9i~WoP\r0eV[5=cJ1gIW_ons~}jZ2]_>絣. op}G>r~3ZnQ/ϕs q?(@_>l&cGA&T/['sڄZyv00.̜yj^ZǷ\!A7?4-v6ί?{V~gk4zrM#7UW/[]"~[LE-]Uhݼ69cҸ;=K=>ݗK#oÂٓ;\LUgvG]Ǭz{kn~`E~ƚk{U<~B]_{ V}㋥ lU[]nﲻKö<9\o0_ :6X4uTBuwV;JQ{wX⏄Ҥ1}'~|Ş=N . ;_W\vWX䗯|TUeT┆4Ӽ?CV+8֞+dp396FUBaFk߹9QƩ:HW$ !L*6ɐ޸b$yVFt(-.? _v&[;fwG!C,Ydr%S^ei~ʊ⤱ [k3Iǁ(Q yLiwzN3k?XB63ECZ2Nw ax:%o~hA=Ic0VNk%Q!̑yЎ ;&[5ai[PBTS-t^H|aq(,YQ(\-آJB%9?A?6p-Z0uکh=nT6sf:y.+Tg~.A#^)-=hdp E6 cSf95Y$VGXQ{H[W:׼i>PkV`1Tp2$iiVmffj`^AI{'>/V(% ;ưM3:)*5IlkZ 8(hκݱ$ Ј_q"=;:! 2'n8nw.~vks59}gk(>š@_`)Ɩj6"$ |:ϖ ޙڿ 8gV4DńMmU\ 9'.]>cRgr4il/%=X  Cr 3(hFE 5\ PztLAè<ҁf(_q7p{=øuDfrVoغ-5ֱ{piFl6쯪ߕ A:U~ =[ dڊZҔǺHQ u#9@G , 18O91'Cr 5LDAςh18k'Cx0QՁRZJ͟Z'l^x@UE\fc(E,OHJŘbc 8" UZ>n^H=IR]/V䈆V?{.-F_a5 }ߞ(| Ys qofp=.q @lrˈ>6:>inKXy /xIRMVҝH93M!M5,|R p_Z9:d4!!. sGKmzpYF@/z9L RF{(O3(Jq!Pqlm rs Ijk pVd=E t["#0[]\n9>-zLo1j|.Q8bih .i}Bmwt1D?4P&9{fK~!%gB*Bw4ۏa2v ~%?Kuqe^QD!Li9=  ZFkъK0 +!oDmЋĴ5,OB"J"Y׵hdX0H@⤑gUK ##' Og#OĆ^Yjs]UW۵v}RޭR Ej"P`L !@b Eb$@l7૖TЖ^.=ks-+w{=fffzz/µxѵqE{G{Nw{|ßE?}̅sխ?_Y-G`}֓oܟszppx˕z ?SWN󕋿up;?~}q>? j^ N1mߞ8>Kyc~_q[,([.}n~yc+-=<+.E?p쒇g\.蜽{vvw/\/_{.8kn틾/^t 0 r4[sol1*jppz?+#{ @Ïɞ vkPait=璡\ZEYŊLeȏ|H X!R" !R/HQ2.6.o"@ANrNܥ:@g/&%E01'I7:\㜸v3#O{xR8geE. X⼝Ű8z=}|}nsԖ:x r%25G3#pofN ˁkC=@Z>QaI.-Bq_u 401^> a?̈sD^}UMA^pXDžH%-,dϤ؊2; [=Tԏ9Qg|fL6)cKK^`;Z=xƥ:x;r|?{rW~w#sO?\苾7aj~<ϿW/dxѽy?  uG>5q#Ұ H8p9͗QSۻ<{>K}`=k.>+ݷu/_/o&\#'k_]}SO'}և׽>O,7s_{_Mpb1g/MaD7⟾~/o>O?vՑ㫷-\tO_|zʀk6ШxdZK)HgiML+m[ugє?MSB:!Q i}ڔ}2xcojcp/3ʚYmrB*Ou1i/LGTFi1 b xCƼ6Y[_547@<DuXN_F'e.4=]ϐ/#1k)X=&-?*׼*Zߩq~Wa5 +&i\S|MlւWYLrVo+9pܚM΁&PaDN/ٶB,֭ovF)RZjUmPٕcD0.l^=],Wm[ :\ e}~d{bPv |]UfP^UbM›q~l[W!Q=gq S4. '#+E{~TmN$BAe2ORȷW9YW-&k-wdT)z51g<绥Ţc.Y8HL[Uƺ{Mԏhql1ࡽ Ig%3]3=$VھZZ ,ĸ)'K Sö'âo$ʟЭ "a;ﵸQ0ex qA@J@h[1y_[KkK$%(|T0 (bIs4-h;и7Ǒ`\p?43x\ΐ`=GQV 4G=-T b>5ߨođNt(yq H͗Lw``S6U&nT 1s[λeL m3r-sgjw1j1LS4ңySz>.y}7w鹄"8{!S^orIynĆjd>maEja۬7 C@$eje_&4w1Id}jLrPЧcD܂Պ¡MhXœ$_j3V>2ɑ4.:KLrزV%2Kc\&Ȱ2ȸp (/ETlMrS^ctkӎ~ RUgF&\Z ;N['!zMHE{֞)?uSYؚyb&FUc=  ȩ0<5l8;Ѧ&7 >$ >O/0uOKg9-pQB edF![h+Ce"' j|h `G6qefT<{[2H(,;:nzm 9"G \"4h"j^Hj[<ּL{`;=Rڷ!M+AYa#dL㷹cn:'ҫ`VNY C ,D"IƊFVPb1;GBdjx3̨Jq@/dJ4]6/KX ~ׇ :,FJaP1S4 V4PfjL2"u0,0 x8D-dR MP.:o^jh]m׀/JJPl#@= 91:03Y$fm|$XJHf>h[GYglnw@ay^ͤb9V!hřH4׬\˟K*CMj黭ؚhLjXfЮ$I(E@AwTAuZ۾u>s/A`YN|7qq1" x-zE^b& ! 59 1`|ujeH~ïڴJ+1fb5L,qc0eZN#K^hg#T  A.qq"&fKӦ'S`Zn$_9eGylk̬B=" 9 pk 'mLR2@%:)⶧di%`FG!oQN#gaPgіW ͋d2B gq:ɱqðŰ3 KY aZ2$Ӻ:.V髍RDgZt;s@ϑTraD]LMoR]ko[FtwDܵ3N7}I,ldԋ\ӝɍyif|\aši$tlQu{b-A^_*27[?I: 3pi҆~OVw!.&tmI4Q5ny{n\?'O>v[\ #wGS'vL3TlJ;r5rAv"vȷ?36ɎFWC׺}MIFq hlH~N%ޔ5Tojq?.= #oR䥢GefqUGoG5JVӪC CN7sGL&-Z(;EU=QL_#Jfݎ(+;5kR}$293p"?DA`?"p_!vG],ldrvYv1M:.EK?%PVY1e=5)Q30wL+CFxPN.<+Lw(= cm3} V+v+ !Cofy$f=om2l uLCKpdo ˃.#S1%wP;6mhF'ᝮjraMd8ٿwg8v$یPKv^#!ԿyH@pubD' xg9SQCuWZ!Mhem;lL::(e+ *Z`B2J*gAܕSc/N!4z)]U*0ݪYyiLӎ<9-UUHÖ0|OԨIӾ ά5mL䉮`#T斴Ҁゆu|YNRWNyrf\I37riab3g88 Y2L9ܺ$1f٦rٖ99(<+U*!28`7"?Mm-< JJ}R,@E"~ qSj6 ͂i̠7_V!嘖0tM{ _C dj vܯR=u~rX;zD!5+I-1<@DR1gg$:~~ C&AS]ɁQp=ЅOԘx)v/r$Bk^VTg!;:Cɳ6CѨggSʒ]^3f0:'T4Pn^J0]zgd5w;c}}b2:JF-<`ul@`cvd3LJ'%zɊ[/{h8oA:5Zb`䫔3&\*& B .-^!+q$jgtd Qj0RMkֹR/Vێ xM^~?xp$Q-QX%NŞv-17`Ʀh_[}H,&GZ1n{[[ulU}Mv9$+)F3MW @pURE39O!Ln:)x^n~妷|J83Ԯ1A:oȐgJ?j|+Z<[ blSK[c 2q=Sɩ YIbhE֊.6*Tpc8aS%6H.ctn\48[Uwfz$@+0(  s `d}4Fִ};Rq4^#88o щE Rpo¦sf/ ɭo:6eYMѷz1"5zL-ʺ˼g!RQKްuf @ d6`ΘiP%sKfgNX]i E\^Y( մЉ5sBaXbhy&fd+Mdqr%X&) ElA6Zu!Uhϑ'%')+˵ wխR`S}5>aۆ cmÝ\ex͏]9-^yN64O4~nS#6K64fA , Qje"B"uXtl '#Tr^}s:s%AJJkm4:M6O &4Yzn),+Xsvh11R[vGndUI&(VҮS1767)=1No> ;*xႡgQ9bb6g R2Iab G /xZ"u#@^~;6FCgsLiWC-젦;24f,P;EPl q8TC/dQRI *~Crls#1G^lόD#YK3[vJ| }|Dnxcvu~uTT@M(EHyà6{ʬ\ :m}"[NY״[{0fZuoų9 *C tBߗ'pu5ѷu9,U |ݘu0N~X촜+*pg a"3WOCs P!*w`YH pAyv9ӝOęs,̭ӼWt[fKr7!@¯qh!"PO$IDATӑEܑ + |MhtbsV6 Oirs &54Q{ %$ru$,<Ī tﹸ7*H< bn۽Y0*ĭLwp V,dt ^gM\5Z_c}vOIbgX Cz 5䝸`C]ͶTXֶ d 31e=`t=. ) ]nK:Yr=$3vDn*򀤠v Đ昨ҼH-Z4@ ~ _f_=ł_)Gr,St^t -.64A hjk|YGu՝=Yu:|)+m^vs$q3.N+b^l^6 _Q3"tK \HD+NKP:.,'P ]2AĕAx4^e!sWyVpYLؓ\{4SmtF&|S>eA|Ȟ!^*k8鈢OtQsYXbbI@k1D?"]4NIENDB`dtkcore-5.7.12/docs/src/layout.png000066400000000000000000000433711476226660600170320ustar00rootroot00000000000000PNG  IHDRmHɦ IDATx/ؖ PE!*$ HIP B"EBRbbh`)$R "T2d )(˨g{s|fvޝw3sy9ϼgzT@T`~7 a0 n\[8sݳOaXm{T@T@T@Y2ga `8ڎ] \I0 YlΑIbכXh^-]T@T@Kja֭[0mf:ݔ>vSZPPPW`k!Qav0 ڎ_X#PP@YK@ #mb'NkKRPPE)e6ﯗIxi&.i#Y-PP8~f-7mcˡ$˪:Use3ϐ[9jMxQOmjأ GJx=['{Y!smRSPP#V(p4-jbk痨s~,ԯ_3%Qm}Fܹ&ޜ:xS/WXzk@:ZB[UsPP8Q.`qJ}TS0%6@9yu h֧?56[-?{Y5 \@Kn [#2_,K0W{c[(axX씟G`#0֭։4dg5ic (mKU3|***G@ &KMFo@ emM7T@"͔z\fis k[['66.k')c xz*LU U HSC-NůLk^mmmYھm***G@#Th[9[ zcTinMBXgu1iwsҴ:~UY<3+։xs74Z%g4/mx -`<PP8!~qk9qNMދ)|7ixe H=I_t,QmN@,zdPֶoVPPP'`M-E m?=J~ m](K6ƫ9GږSM= @@i[uv]o$K?Fsleɲ۷zm@l@hz+{dW@1tO>d]w}(s ,Y=f|-$ hfBdh{GP{W/&k&mŽ܄^Ba>վmgBh{_0aO1,I mBa ^ڀ6pn6 ]b$%lwPSro_ж:ngh-enmNڈ6 +@ۧ~6LۆaR OPwu\[~գG^J7߬gI<8۠Z˲_|?|kH9?x`O"?~tIx<oq@/Yxٹ>'&6e!sM-m uHC|՗_~1J<~ڞڄ6 ,aB-6&qLLL޸hr LNM&S^@W ;p0'5W皴ȳQ፸RI&=cS\S<[6_A:!'986 hK؀v h(v 34#kÑN{L& X&ף Q5]82`o >uH]yΜS'{~mk#!<.mx(yi Q6yUϡv4ۊm;|f^X==}<dBh p4(3y2 )zjy6&xLmovkYLxO;O6S/',p(UJx U5WpS6""֧IH${:v>Pts>[^ruѰqvڶ@ ,ۨ1/>1ygH8ƛym rj )2,;4m#,KG {B[_MǀT55_7҆ќ W冗 4-MlAԇ2+U uϳp$<:g[/>䉭#ɗ>MK}_ Paϴ0F%vOw6oWkAKm`.І}?QCƠ-}.nU9֎aB7f 3  iO 䛰9@9G@-=&}B[s[?gdmh jc]fm PC2bOmIr1h/]ԍ?؜!l@h1x6]Z[5BD<+19}//}\po= s5my/(0r:KxxjIOj?%^g7:Pc>ڀ6 hMhJm@NhCлe hڀ6  mBoWڀ6 hڀ6p6 @#so> hڀ6pڄ6߮m@ml@h;F:[oڀ6 hqۀvBO?~w5m@f?b @*=|***6\aw>|w^z muRc m ~ mAPPP m]rfU@T@T@]0kq6 l. mԈ***B.߸BOT@T@T`B~Al܄fjDPPPmo\***0[m KnBl35 ж f7fSPPж_%7mQT@T@T@hWh?U@T@T| b&uӧOWo^j * Y+5_]aVnsKPP8o. mM{ݻkhɓ&***p m`~ m߽xb+ OWxT@T@T@VO={:믿^ݻwŪesJO/l6m=*#C}rPP( Maղ1h#?ê + - fS mxeׁ~; BV-{Oh[K*;WjS}zPPW@h[̦r:ݏ׀67PPP* MaղJhb btB[ mQ RPPm+u PPƲ셶N:**B4U-|WhtA#A*** -e m.(uD1HT@T@iZB[GT@T@T@h[˦:]Phb mT]( ж0Mg/u PPڦjB[ mQ RPPma,^htA#A*** MSwN:**BX6B[GT@T@T@h m.(uD1HT@T@l:{( 6MU :]Phb m ctB[ mQ RPPm+u PPƲ셶N:**B4U-|WhtA#A*** -e m.(uD1HT@T@iZB[GT@T@T@h[˦:]Phb mT]( ж0Mg/u PPڦjB[ mQ RPPma,^htA#A*** MSwN:**BX6B[GT@T@T@h m.(uD1HT@T@l:{( 6MU :]Phb m ctB[ mQ RPPm+u PPƲ셶N:**B4U-|WhtA#A*** -e m.(uD1HT@T@iZB[GT@T@T@h[˦:]Phb mT]( ж0Mg/u PPڦjB[ mQ RPPma,^htA#A*** MSwN:**BX6B[GT@T@T@h m.(uD1HT@T@l:{( 6MU :]pWhW+f{7fg{キ裏alڀA4/\quV '| &GPPжg5ֱ]ӧ~{ ˛''uW(4A_b#Bw}/K)@~0  eȜ%RCʩO8 qRc.8=~xW_}q V{55<Wt1h>:` @$o6&< kL.U IDATvS87PPBs 0)P 0\8.zw{ mgm,e޽{wm,_b|\xtE\`"mt|77 @ c2*˟l6#M zI0 B@@4K`0Rü{ L++ݾ}{=W_@sR E68H.}AaݖE{0qK9Ofy/Q%]OƷdu5FxeT:΍̓s\32_um@gOkh#/1R!p],X-=fO{ D׽CuץW~L?6mϸ*6@s_eCu/Tqj0o/ ʜG&scΓe 0WᎰHcGx3a?⑛ڮ *i3qUw)KI$~~> [ )f5l9o\@ r<ȇ;@qy%MM5q* qb: P Jq^v66T`u9s-qSx1 ,imqh$V 7X}Xʒߊ pF\_l &{o@yۖP h4~ pCGQ8{ : Cn*ppX_&inV26 TՁ9BˢI$Su(KO dhuΝx֭6 1ms6 Ơapr ̥v]xxKX ʆ'@79a=e4ϒeEҳsΠnE`g@]fA;&"k:ؘj9'1xeg<5/VGq6yA%>c!/D3 V7m6LhD+ǣ1ֆBy 7)yKdbZhK~DƄcpC@[ ?0θ_!A̱ƥ_&"=Z~E8L/e–-pB[m 0@WfZv&X@oCh'=w"˯ڢ@i Z,2mԗ⒆a~K7V~V/+(g:ڦ)(1V1nOs^˄ mϞ]IL R+>0Bd6ήSޏ}@:oNhasq H6]Ʈv->60˰U 0岏 ˲x߫_/][wKSL2Phj))Bs)ɼ |ʑ~H8cXkґw >7\@z0y~jġ7mW6&7+# ҰcβhèXaHl6y.f90fu:VIN6UsG_ڪB-12HsX󂹏q9p/^l 'cYo˧%)K4ɛL<7I8/~6L#p@H}$BiBPGY]1GeiR}@1efcV3ISGG<p6ꖍ0wg$ hC>S 2<^=;; ޴)mHǻS ۈ26ǎ]F pWJ6 [+ԍ84V8͙AƠICiz8l aɗpрI} N1KkF$İk^?Ni12v~+4\eciiHwUh@Q[. ` qs U*ES")#c܍q4yI阐ȫ9IsڕnB[USTm̯4PHG? ,i`$[hcK< \/r1Th+.F tD4Ziq5L݄v[ӫ -e^=YCTR4/msj|fPP* -?=ڱCN * CwN:**siWNGO\uQPPӶ?m<=m{ PP6NT#u PPfEm.(uD1HT@T@q:( v4/BhtA#A*** m.(uD1HT@T@xB[ mQ RPPmpGhtA#A*** Ƌ:]Phb mDu;B[ mQ RPPh6^B[GT@T@T@h':]Phb m@"N:**B8QB[GT@T@T@h;!u PPƉwN:**Bl( 6NT#u PPfEm.(uD1HT@T@q:( v4/BhtA#A*** m.(uD1HT@T@xB[ mQ RPPmpGhtA#A*** Ƌ:]Phb mDu;B[ mQ RPPh6^B[GT@T@T@h':]Phb m@"N:**B8QB[GT@T@T@h;!u PPƉwN:**Bl( 6NT#u PPfEm.(uD1HT@T@q:( v4/BhtA#A*** m.(uD1HT@T@xB[ mQ RPPmpGhtA#A*** Ƌ:]Phb mDu;B[ mQ RPPh6^B[GT@T@T@h':]Phb m@"jŋ/yucUPPV9ٳg'׫{sжZ0 [OuGU@T@T@h>6ﭷ6n|=UT@T@^Mh;%Ϻz7sPP8K6ڡGnw]=x,;**BvƯFm{W?ThkPP8G6( p ڄ6޶7|>***Pڄ6_C?NpSPP mBQAsSPPBvt[JT@T@T6Mhs,PPPP@hڄVQT@T@6MhsPPPP@hڄVQT@T@6MhsPPPP@hڄVQT@T@6{sw5m@f/V?lw{y}{}wyž36 hڀ6зmƦ. hڀ6 \6m[;;ک6 h m7 ?cA솵X6]g>lW_Oh!ӧOW}۫W_}6 h@lw] ðɓ; m7>|zW md>@'/\i[y6 k~C>7[P" c=Sґs e_%KMivԙԅ<)<@m6  cp 8)q 4D,9>QG˼秽vEJ*v@ (c`X\FlaTA?˫q6 5M+J&q&/ʦhki@fWB>@v$ |-]_1/ \㑾oFk*cYvؗ mgmxjDLx-r^1!&D 87mc1aVhHϤ `qD]c,u |_RW!O/XMY. m3bճu쉶bP:/ahE`xB<ۭm`ư%'}u'2R"=qtSN6ғ;uGQmy1 ϝ8ۆfB[3[>:P9 & "?&1yd(e xa%/ddDx#_en79C&>z\_[& )uڍ @68) &~@ Ђc'Is*ױl ~HG<^k _H"ǀyO}Ob5 `& ~G1x['yRFTq~6鸎r8n䝗 +:m@g}!՗ "oWySGcsm@h.&Fc<@S#nk %)8x Ӂ`H'ȋNh=mZ k!]:eOIDATkPq@ .9yi{ٶG9VڄXz9VbE 8 h5y%ď ̀<@k!kO.SG:Su6¨'G7 "ԟz΁6ϭ~UaB&i'e@5vheS(q.qGj\/`wf@N=#OgL2/#WB)ĻF:ʦQH>=2lrG7y?iҤxt$9a_LF9˴;`A cX* mڀ6 -@ uʟ X t65 WXml@hhڀ6 h ؀vtno>oڀ6 h6p vo?0 58Sۇ eP5m@NN^ Ν;oݺ_v BC]ڀ6 hS6w'Q}Koɶ hWS6 -c.CsWAm@8-w?w˟'>:cڀ6 hڀ6p6r**********************************O,޿3SRPPP=(<5{ܹ۟|U@T@T@QN0 : .]? _]h[ZuWPPUm8Vy1 óavw-hn@m@*Y㪼_7HhC4.F!***Ǣ,l!ܺu~v6m )6xeu=ZpLKUQPPؗ8EؐeS7PPP8&3MT@T@T@T@T@T@T@T@T@T@T@T@T@T@T@T@T@T@T@T@T(H__ PPPP__ݱgq3G&_o-MT@T@T@T ,Bc=%< +Gr?mf眍{lǓN@ߓaK@q=, _!S8(l_Xb{6`-^U4 ěGꅫւָWvywSPPPQ|G ; '] 0փ uQT@T@T@T`xe(K8'{lıKǻkci=H sSP ?zc+IENDB`dtkcore-5.7.12/docs/util/000077500000000000000000000000001476226660600151655ustar00rootroot00000000000000dtkcore-5.7.12/docs/util/dabstractunitformatter.zh_CN.dox000066400000000000000000000063261476226660600235030ustar00rootroot00000000000000/*! @~chinese @file include/util/dabstractunitformatter.h dabstractunitformatter.h文件提供了DAbstractUnitFormatter类, DAbstractUnitFormatter是抽象的单位格式化工具, 提供统一的单位格式化接口 @class Dtk::Core::DAbstractUnitFormatter include/util/dabstractunitformatter.h @brief 抽象格式化工具基类 @details DAbstractUnitFormatter提供统一的单位格式化接口. 在DAbstractUnitFormatter的设计理念中, 不同大小的单位被编号成不同级别的单位id.
id从小到大, 单位从低级到高级. 各相邻单位之间的进率可以是不均匀的, 实现者只需实现unitConvertRate, 返回当前单位到下一高级单位(从id为x的单位到id为x+1的单位)的进率是正确的.
事实上, 实现者如果保证unitConvertRate对于任一id为x的单位, 其到id为x+1的单位的换算比率(允许小于1)是正确的, 不需满足id递增, 单位级别递增的约束(即unitConvertRate总是大于1的约束)
注意, 实现者此时需重写其他接口以同时保证正确性. @fn DAbstractUnitFormatter::DAbstractUnitFormatter() @brief 空参构造函数 @note 注意, 该类为抽象类, 不可直接实例化, 该构造函数仅供实现子类使用. @fn @pure virtual int DAbstractUnitFormatter::unitMax() const = 0 @brief 获取最大的单位id @return 最大的单位id @fn @pure virtual int DAbstractUnitFormatter::unitMin() const = 0 @brief 获取最小的单位id @return 最小的单位id @fn @pure virtual uint DAbstractUnitFormatter::unitConvertRate(int unitId) const = 0 @brief 获取当前单位到下一高级单位的进率 @param[in] unitId 当前单位id @return 进率, 正常情况下, 大于1 @note 下一高级单位指id为unitId + 1的单位. @fn virtual qreal DAbstractUnitFormatter::unitValueMax(int unitId) const @brief 获取当前单位的最大值 @param[in] unitId 当前单位id @return 单位最大值 @fn virtual qreal DAbstractUnitFormatter::unitValueMin(int unitId) const @brief 获取当前单位的最小值 @param[in] unitId 当前单位id @return 单位最小值 @fn virtual QString DAbstractUnitFormatter::unitStr(int unitId) const = 0 @brief 获取当前单位的字符串表示 @param[in] unitId 当前单位id @return 单位字符串表示 @fn qreal DAbstractUnitFormatter::formatAs(qreal value, int currentUnit, const int targetUnit) const @brief 格式化数值到指定单位 @param[in] value 当前单位下表示的数值 @param[in] currentUnit 当前单位id @param[in] targetUnit 目标单位id @return 格式化后以目标单位表示的数值 @fn QPair DAbstractUnitFormatter::format(const qreal value, const int unit) const @brief 格式化数值到合适的单位 @param[in] value 当前单位下表示的数值 @param[in] unit 当前单位 @return 格式化后的合适的数值和单位 合适是指: 如果单位大于unitMin()或者小于unitMax(), 会尽量保证值被转换到接近最小值的合适单位上. @fn QList > DAbstractUnitFormatter::formatAsUnitList(const qreal value, int unit) const @brief 包括完整转换数据版本的format() @param[in] value 当前单位下表示的数值 @param[in] unit 当前单位 @return 格式化产生的所有的数值和单位 */ dtkcore-5.7.12/docs/util/ddbusextentedabstractinterface.zh_CN.dox000066400000000000000000000143541476226660600251570ustar00rootroot00000000000000/*! @~chinese @ingroup dutil @file include/util/ddbusextendedabstractinterface.h 该文件提供了一个扩展DBus接口工具类 @class Dtk::Core::DDBusExtendedAbstractInterface @brief 扩展DBus接口, 继承自QDBusAbstractInterface @details 和QDBusAbstractInterface相比, 该类连接了org.freedesktop.DBus.Properties接口, 提供了异步访问属性的接口, 可以方便地通过此类进行异步DBus通信.
同时此类提供了属性改变信号的分发和中继. @fn DDBusExtendedAbstractInterface::DDBusExtendedAbstractInterface(const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent) @brief 构造函数 @param[in] service 该interface属于的服务 @param[in] path 该interface属于的对象路径 @param[in] interface 该interface实际连接的接口 @param[in] connection 用于连接该interface的DBus连接 @param[in] parent 父对象 @note 该构造函数受到保护, 只有子对象才能访问. @property Dtk::Core::DDBusExtendedAbstractInterface::sync @brief 是否同步获取属性 @details 当sync为false的时候, 在调用属性的get函数的时候会一直返回空值, 解决方法是监听属性的changed信号并自行保存一份缓存, 让changed信号修改这个缓存. @property Dtk::Core::DDBusExtendedAbstractInterface::useCache @brief 是否使用缓存 @details 如果使用缓存, 在内部获取属性的时候将不再进行DBus调用更新属性. @fn inline bool DDBusExtendedAbstractInterface::sync() const @brief 获取是否同步 @sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) @fn void DDBusExtendedAbstractInterface::setSync(bool sync, bool autoStart) @brief 设置是否同步和自启动 @param[in] sync 是否同步 @param[in] autoStart 是否自启动 @sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) @fn void DDBusExtendedAbstractInterface::setSync(bool sync) @brief 设置是否同步 @param[in] sync 是否是同步模式 @sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) @details 该函数内部实现调用[setSync](@ref DDBusExtendedAbstractInterface::setSync(bool sync, bool autoStart)), autoStart参数值为true, 即默认自启动. @fn inline bool DDBusExtendedAbstractInterface::useCache() const @brief 获取是否使用缓存 @sa [useCache](@ref Dtk::Core::DDBusExtendedAbstractInterface::useCache) @fn inline void DDBusExtendedAbstractInterface::setUseCache() @brief 设置是否使用缓存 @sa [useCache](@ref Dtk::Core::DDBusExtendedAbstractInterface::useCache) @fn void DDBusExtendedAbstractInterface::getAllProperties() @brief 获取所有属性 @sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) @details 该方法会调用org.freedesktop.DBus.Properties接口的GetAll方法, 获取所有属性并且发送属性改变信号, 如果是同步模式(sync为true), 该方法会使用同步调用call.
sync为false的时候会使用异步调用asyncCall. @fn inline QDBusError DDBusExtendedAbstractInterface::lastExtendedError() const @brief 获取上一次的错误 @return QDBusError 上一次由DBus调用引起的错误 @fn void DDBusExtendedAbstractInterface::startServiceProcess() @brief 启动服务进程 @details 该函数会调用org.freedesktop.DBus的服务的/路径的StartServiceByName方法启动DDBusExtendedAbstractInterface对应的Service. @fn void DDBusExtendedAbstractInterface::serviceValidChanged(const bool valid) const @brief 服务是否有效状态改变信号 @param[in] valid 服务是否有效 @fn void DDBusExtendedAbstractInterface::serviceStartFinished(const quint32 ret) const @brief 服务启动完成通知信号 @param[in] ret 启动服务的返回值 @details 启动服务是调用org.freedesktop.DBus服务的/路径的StartServiceByName方法, ret为StartServiceByName的返回值. @fn void DDBusExtendedAbstractInterface::propertyChanged(const QString &propertyName, const QVariant &value) @brief 属性改变信号 @param[in] propertyName 改变的属性名 @param[in] value 改变后的属性值 @fn void DDBusExtendedAbstractInterface::propertyInvalidated(const QString &propertyName) @brief 属性失效通知信号 @param[in] propertyName 失效的属性名 @details 该信号会在DBus属性改变但是本地反序列化失败的情况下发出. @fn void DDBusExtendedAbstractInterface::asyncPropertyFinished(const QString &propertyName) @brief 异步获取属性完成通知信号 @param[in] propertyName 获取成功的属性名 @fn void DDBusExtendedAbstractInterface::asyncSetPropertyFinished(const QString &propertyName) @brief 异步设置属性完成通知信号 @param[in] propertyName 设置成功的属性名 @fn void DDBusExtendedAbstractInterface::asyncGetAllPropertiesFinished() @brief 异步获取所有属性完成的通知信号 @sa [getAllProperties](@ref Dtk::Core::DDBusExtendedAbstractInterface::getAllProperties()) @details getAllProperties方法并没有返回值, 须监听此信号以实现完整功能. @fn void DDBusExtendedAbstractInterface::connectNotify(const QMetaMethod &signal) @brief 信号连接通知函数 @param[in] signal 连接到该对象的信号 @details 该函数重写了QObject的connectNotify函数, 当有某一个信号连接到该对象的时候, 该函数就会被调用. @fn void DDBusExtendedAbstractInterface::disconnectNotify(const QMetaMethod &signal) @brief 信号断开连接通知函数 @param[in] signal 断连的信号 @details 该函数重写了QObject的disconnectNotify函数, 当有某一个连接到该对象的信号断连时, 该函数就会被调用. @fn QVariant DDBusExtendedAbstractInterface::internalPropGet(const char *propname, void *propertyPtr) @brief 内部属性获取函数 @param[in] propname 属性名 @param[in] propertyPtr 属性缓存指针 @sa [useCache](@ref Dtk::Core::DDBusExtendedAbstractInterface::useCache) @sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) @details 当useCache为true的时候, 该函数仅仅返回propertyPtr指向的内存拷贝. @fn void DDBusExtendedAbstractInterface::internalPropSet(const char *propname, const QVariant &value, void *propertyPtr) @brief 内部属性设置函数 @param[in] propname 属性名 @param[in] value 要设置的值 @param[in] propertyPtr 属性缓存指针 @sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) */ dtkcore-5.7.12/docs/util/ddbussender.zh_CN.dox000066400000000000000000000062711476226660600212110ustar00rootroot00000000000000/*! @~chinese @ingroup dutil @file include/util/ddbussender.h 本文件包含了DDBusSender类和相对应的工具类 @class DDBusData @brief DBus数据存储类 @details 该类用来存储DBus连接的相关信息 @var DDBusData::service @brief 请求调用服务名 @var DDBusData::path @brief 请求调用对象路径 @var DDBusData::interface @brief 请求调用接口名 @var DDBusData::queryName @brief 请求调用函数名 @var DDBusData::connection @brief 进行调用的维护的DBus连接 @class DDBusCaller @brief DBus接口调用工具类 @details 该类用于完成实际的DBus接口调用 @fn template DDBusCaller DDBusCaller::arg(const T &argument) @brief 添加调用参数 @details 改接口符合链式编程规则 @param[in] argument 调用参数 @return DDBusCaller 添加参数之后的caller @fn QDBusPendingCall DDBusCaller::call() @brief 发起实际调用 @return QDBusPendingCall 异步调用对象 @class DDBusProperty @brief DBus属性操作对象 @details 该类的作用和DDBusCaller类似, 用于完成实际的调用, 其封装了org.freedesktop.DBus.Properties的接口, 提供方便快捷地属性访问方法set和get @fn QDBusPendingCall DDBusProperty::get() @brief 获取属性值 @return QDBusPendingCall 异步调用对象, 在完成之后可用于获取属性值 @fn template QDBusPendingCall DDBusProperty::set(const T &value) @brief 设置属性值 @param[in] value 需要设置的值 @return QDBusPendingCall 异步调用对象, 在完成之后可用于判断设置操作是否成功 @class DDBusSender @brief DBus请求工具类 @details 通过该类的方法可以方便地调用某个服务的某个方法. 该类的设计采用链式编程, 多个api都会返回操作之后的对象, 这使得原本需要使用QDBusMessage多行代码完成的调用只需要一行代码即可完成. @fn DDBusSender DDBusSender::service(const QString &service) @brief 设置请求服务名 @param[in] service 请求服务名 @return DDBusSender 设置之后的sender @fn DDBusSender DDBusSender::interface(const QString &interface) @brief 设置请求接口名 @param[in] interface 请求接口名 @return DDBusSender 设置之后的sender @fn DDBusSender DDBusSender::path(const QString &path) @brief 设置请求对象路径 @param[in] path 请求对象路径 @return DDBusSender 设置之后的sender @fn DDBusCaller DDBusSender::method(const QString &method) @brief 设置请求方法名并获取请求调用对象 @details 确保在调用该方法之前, service, path和interface都已经被正确设置 @param[in] method 请求方法名 @return DDBusCaller 方法调用工具对象, 调用该对象的call函数即可完成最终调用 @fn DDBusProperty DDBusSender::property(const QString &property) @brief 设置访问的属性名并获得属性操作对象 @details 确保在调用该方法之前, service, path和interface都已经被正确设置 @param[in] property 访问属性名 @return DDBusProperty 属性操作对象 @fn static DDBusSender DDBusSender::system() @brief 获取 systembus 访问的能力 @details DDBusSender 默认使用 sessionbus ,此接口提供 systembus 的访问能力 @return DDBusSender 可以访问 systembus 的 sender 对象 */ dtkcore-5.7.12/docs/util/ddisksizeformatter.zh_CN.dox000066400000000000000000000033061476226660600226200ustar00rootroot00000000000000/*! @~chinese @ingroup dutil @file include/util/ddisksizeformatter.h 本文件定义了用于转换磁盘大小单位的类DDiskSizeFormatter @class Dtk::Core::DDiskSizeFormatter @brief 磁盘大小单位转换类 @details 继承自DAbstractUnitFormatter, 支持最小的单位为字节, 最大的单位为T字节, 支持修改相邻单位之间的进率, 是采用1000还是1024. 默认使用1000作为进率 @enum Dtk::Core::DDiskSizeFormatter::DiskUnits @brief 磁盘大小单位枚举 @var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::B @brief 字节 @var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::K @brief 千字节 @var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::M @brief 兆字节 @var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::G @brief 吉字节 @var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::T @brief 太字节| @fn QString DDiskSizeFormatter::unitStr(int unitId) const override @brief 获取unitId对应单位的字符串表示 @param[in] unitId 单位id @return QString 字符串表示 @fn DDiskSizeFormatter DDiskSizeFormatter::rate(int rate) @brief 设置当前的单位进率 @param[in] rate 需要设置的进率 @return DDiskSizeFormatter 设置之后的formatter @fn int DDiskSizeFormatter::unitMin() const override @brief 获取最小的单位枚举 @return int 最小的单位 @fn int DDiskSizeFormatter::unitMax() const override @brief 获取最大的单位枚举 @return int 最大的单位 @fn uint DDiskSizeFormatter::unitConvertRate(int unitId) const override @brief 获取unitId对应单位到下一个单位的进率 @param[in] unitId 当前单位id */ dtkcore-5.7.12/docs/util/dtextencoding.zh_CN.dox000066400000000000000000000117731476226660600215510ustar00rootroot00000000000000/*! @~chinese @ingroup dutil @file include/util/dtextencoding.h @details 本文件包含文本编码识别和文本编码转换的公共接口。 @class Dtk::Core::DTextEncoding @brief 文本编码信息类,提供文本编码识别和文本编码转换的公共接口。 @details 提供文本编码识别和文本编码转换的公共接口,默认使用 QTextCodec 进行检测, 若系统环境中存在 libuchardet.so 及 libicuuc.so 库,可拓展支持的编码格式。 @fn QByteArray Dtk::Core::DTextEncoding::detectTextEncoding(const QByteArray &content) @brief 检测给定文本的编码格式。 @details 默认使用 QTextCodec 检测,若系统环境中存在 libuchardet.so 及 libicuuc.so 库,可拓展支持的编码格式。 检测会判断最接近的编码格式,未成功识别或为 ASCII 编码格式,将返回 UTF-8 编码格式。 @param[in] content 待检测的文本内容 @return 文本编码格式 @fn QByteArray Dtk::Core::DTextEncoding::detectFileEncoding(const QString &fileName, bool *isOk) @brief 检测给定文件的文本编码格式,将读取文件头部最多 64KB 的文本用于检测。若文件访问失败,返回空编码格式。 @param[in] fileName 文件路径 @param[out] isOk 检测是否成功,主要判断文件内容能否正确读取 @return 文本编码格式 @sa DTextEncoding::detectTextEncoding @fn bool Dtk::Core::DTextEncoding::convertTextEncoding(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) @brief 将输入的文本 `content` 从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `outContent` 。 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本仍会写入 `outContent` 。 @note 当处理大量文本数据时,需考虑并行处理,防止阻塞线程。 @param[in] content 传入的文本 @param[out] outContent 编码转换后的文本 @param[in] toEncoding 转换的编码格式 @param[in] fromEncoding 原始的编码格式,默认为空,会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 @param[out] errString 错误信息 @return 是否转换成功 @sa DTextEncoding::convertTextEncodingEx @fn bool Dtk::Core::DTextEncoding::convertTextEncodingEx(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString, int *convertedBytes) @brief 将输入的文本 `content` 从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `outContent` 。 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本仍会写入 `outContent` 。 @note 当处理大量文本数据时,需考虑并行处理,防止阻塞线程。 @note 返回 false 时,已转换的文本仍会写入 `outContent` ,同时 `convertedBytes` 会记录已转换数据长度,你可以决定保留或移除转换文本。 @param[in] content 传入的文本 @param[out] outContent 编码转换后的文本 @param[in] toEncoding 转换的编码格式 @param[in] fromEncoding 原始的编码格式,默认为空,会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 @param[out] errString 错误信息 @param[out] convertedBytes 已转换的 `content` 数据长度,若转换过程出现错误,这个值会指向异常字符出现的位置 @return 是否转换成功 @fn bool DTextEncoding::convertFileEncoding(const QString &fileName, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) @brief 读取输入的 `fileName` 文件内容,将文件内容从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `fileName` 。 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本会被抛弃。 @param[in] fileName 传入及保存的文件路径 @param[in] toEncoding 转换的编码格式 @param[in] fromEncoding 原始的编码格式,为空时会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 @param[out] errString 错误信息 @return 是否转换成功 @sa DTextEncoding::convertTextEncoding @fn bool DTextEncoding::convertFileEncodingTo(const QString &fromFile, const QString &toFile, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) @brief 读取输入的 `fromFile` 文件内容,将文件内容从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `toFile` 。 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本会被抛弃。 @param[in] fromFile 传入的文件路径 @param[in] toFile 保存的文件路径 @param[in] toEncoding 转换的编码格式 @param[in] fromEncoding 原始的编码格式,为空时会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 @param[out] errString 错误信息 @return 是否转换成功 @sa DTextEncoding::convertTextEncoding */ dtkcore-5.7.12/docs/util/dthreadutils.zh_CN.dox000066400000000000000000000047501476226660600214030ustar00rootroot00000000000000/*! @~chinese @ingroup dutil @file include/util/dthreadutils.h 本文件定义了线程相关的帮助类 @class DThreadUtils @brief 线程帮助类 @details 本类主要用来进行异步线程调用, 此外本类所有的public接口都是线程安全的 @fn static DThreadUtils& DThreadUtils::gui() @brief 获取以GUI线程初始化的静态对象 @return DThreadUtils& 静态对象的引用 @fn QThread* DThreadUtils::thread() const noexcept @brief 获取DThreadUtils对应的线程 @return QThread* 对应线程的QThread对象的指针 @fn template inline auto run(QObject *context,typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) @brief 在对应的线程执行传入的成员函数, 非阻塞 @param[in] context 对象上下文, 用来在执行调用时判断对象是否存在 @param[in] obj 对象指针 @param[in] fun 成员函数指针 @param[in] args 对应函数的参数 @return 以成员函数返回值类型实例化的QFuture对象 @fn template inline auto run(typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) @brief 在对应的线程执行传入的成员函数, 非阻塞 @param[in] obj 对象指针 @param[in] fun 成员函数指针 @param[in] args 对应函数的参数 @return 以成员函数返回值类型实例化的QFuture对象 @fn template inline QFuture, Args...>> run(QObject *context, Func fun, Args &&...args) @brief 在对应的线程执行传入的成员函数, 非阻塞 @param[in] context 对象上下文, 用来在执行调用时判断对象是否存在 @param[in] fun 成员函数指针 @param[in] args 对应函数的参数 @return 以成员函数返回值类型实例化的QFuture对象 @fn template inline QFuture, Args...>> run(Func fun, Args &&...args) @brief 在对应的线程执行传入的成员函数, 非阻塞 @param[in] fun 可调用对象 @param[in] args 调用对应的参数 @return 以函数返回值类型实例化的QFuture对象 @fn template inline decltype(auto) exec(T &&...args) @brief 在对应的线程执行传入的成员函数, 阻塞 @details 本函数是run函数的包装 @note 调用此函数的一方需要确保对应线程有事件循环, 否则会无限等待 @param[in] args 参数包, 具体含义参考run函数 @return 传入函数的返回值 */ dtkcore-5.7.12/docs/util/dtimeunitformatter.zh_CN.dox000066400000000000000000000025001476226660600226240ustar00rootroot00000000000000/*! @~chinese @ingroup dutil @file include/util/dtimeunitformatter.h 该文件定义了用于转换时间单位的工具类DTimeUnitFormatter. @class Dtk::Core::DTimeUnitFormatter @brief 转换时间单位的工具类 @details 继承自DAbstractUnitFormatter, 支持最小单位为秒, 最大单位为天. @enum Dtk::Core::DTimeUnitFormatter::TimeUnits @brief 时间单位枚举 @var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Seconds @brief 秒 @var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Minute @brief 分钟 @var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Hour @brief 小时 @var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Day @brief 天 @fn QString DTimeUnitFormatter::unitStr(int unitId) const override @brief 获取unitId对应单位的字符串表示 @param[in] unitId 单位id @return QString 字符串表示 @fn int DTimeUnitFormatter::unitMin() const override @brief 获取最小的单位枚举 @return int 最小的单位 @fn int DTimeUnitFormatter::unitMax() const override @brief 获取最大的单位枚举 @return int 最大的单位 @fn uint DTimeUnitFormatter::unitConvertRate(int unitId) const override @brief 获取unitId对应单位到下一个单位的进率 @param[in] unitId 当前单位id */ dtkcore-5.7.12/docs/util/dutil.zh_CN.dox000066400000000000000000000021021476226660600200150ustar00rootroot00000000000000/*! @chinese @ingroup dutil @file include/util/dutil.h 该文件定义和实现了一些小的工具函数. @fn QString DUtil::escapeToObjectPath(const QString &str) @brief 将字符串转义成符合DBus ObjectPath规则字符串 @param[in] str 需要转义的字符串 @return 转义后字符串 @attention 不要传入完整的dbus路径, 否则'/'也会被转义 @fn QString DUtil::unescapeFromObjectPath(const QString &str) @brief 将DBus ObjectPath的部分路径转义成原来的字符串 @param[in] str 需要转义的字符串 @return 转义后字符串 @fn QString DUtil::getAppIdFromAbsolutePath(const QString &path) @brief 从desktop文件的绝对路径中提取出AppId @param[in] path 文件路径 @return 代表AppId的字符串 @attention AppId可能为空, 代表无法获取AppId @fn QStringList DUtil::getAbsolutePathFromAppId(const QString &appId) @brief 从appId中获取符合条件的Desktop文件路径 @param[in] appId app的Id @return desktop文件的路径 @attention 可能有多个desktop文件的appId相同, 所以返回所有符合条件的列表 */ dtkcore-5.7.12/docs/util/index.zh_CN.md000066400000000000000000000003351476226660600176170ustar00rootroot00000000000000@page util util--DTK工具组件 # DTK util ## 模块介绍 该模块提供一些实用工具用于开发,包括: + 同种数据类的单位转换接口 + DBus接口工具类 @defgroup dutil @brief dtk实用工具 dtkcore-5.7.12/dtkcore.cmake000066400000000000000000000144731476226660600157260ustar00rootroot00000000000000set(LIB_NAME dtk${DTK_VERSION_MAJOR}core) set(DtkCore Dtk${DTK_VERSION_MAJOR}Core) macro(add_sub_dir dir) # message("add_subdirectory(${dir} ${OUTPUT_DIR}/${dir})") add_subdirectory(${dir} ${OUTPUT_DIR}/${dir}) endmacro() message("Current Qt Version: ${QT_VERSION_MAJOR}") message("Current Dtk Version: ${DTK_VERSION_MAJOR}") set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set (LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") set (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/dtk${PROJECT_VERSION_MAJOR}/DCore") set (TOOL_INSTALL_DIR "${CMAKE_INSTALL_LIBEXECDIR}/dtk${PROJECT_VERSION_MAJOR}/DCore/bin") set (MKSPECS_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/qt${QT_VERSION_MAJOR}/mkspecs/modules" CACHE STRING "Install dir for qt pri files") set (FEATURES_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/qt${QT_VERSION_MAJOR}/mkspecs/features" CACHE STRING "Install dir for qt prf files") set (CONFIG_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${DtkCore}" CACHE STRING "Install dir for cmake config files") set (DSG_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}" CACHE STRING "PREFIX of DSG_DATA_DIRS") set (DSYSINFO_PREFIX "" CACHE STRING "PREFIX of DSysInfo") set (BUILD_EXAMPLES ON CACHE BOOL "Build examples") set (BUILD_VERSION "0" CACHE STRING "buildversion") if(UNIX AND NOT APPLE) set(LINUX TRUE) endif() set (BUILD_WITH_SYSTEMD OFF CACHE BOOL "Build with systemd") if (BUILD_WITH_SYSTEMD) add_definitions(-DBUILD_WITH_SYSTEMD) endif() set(CMAKE_CXX_STANDARD 17) # CXX FILAGS if("${QT_VERSION_MAJOR}" STREQUAL "5") set (BUILD_DOCS ON CACHE BOOL "Generate doxygen-based documentation") else() # dtk6 not build doc set (BUILD_DOCS OFF CACHE BOOL "Generate doxygen-based documentation") endif() if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wextra") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -pie") if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(BUILD_TESTING ON) endif () string(REPLACE "-O3" "-Ofast" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") endif() if (BUILD_DOCS) add_sub_dir(docs) endif () add_sub_dir(src) if(BUILD_TESTING) message("==================================") message(" Now Testing is enabled ") message("==================================") enable_testing() add_sub_dir(tests) endif() if(BUILD_EXAMPLES) message("===================================") message("You can build and run examples now ") message("===================================") add_sub_dir(examples) endif() add_sub_dir(tools) if("${QT_VERSION_MAJOR}" STREQUAL "6") set(DTK_VERSION_MAJOR 6) endif() configure_package_config_file(cmake/DtkCMake/DtkCMakeConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkCMake/Dtk${DTK_VERSION_MAJOR}CMakeConfig.cmake INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}CMake" PATH_VARS TOOL_INSTALL_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkCMake/Dtk${DTK_VERSION_MAJOR}CMakeConfig.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}CMake") configure_package_config_file(cmake/DtkTools/DtkToolsConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkTools/Dtk${DTK_VERSION_MAJOR}ToolsConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools PATH_VARS TOOL_INSTALL_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkTools/Dtk${DTK_VERSION_MAJOR}ToolsConfig.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools") install(FILES cmake/DtkTools/DtkSettingsToolsMacros.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools" RENAME Dtk${DTK_VERSION_MAJOR}SettingsToolsMacros.cmake) install(FILES cmake/DtkTools/DtkDBusMacros.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools") install(FILES ${CMAKE_SOURCE_DIR}/cmake/DtkTools/DtkDConfigMacros.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools") if (NOT DTK_VERSION_MAJOR) set(DCONFIG_DEPRECATED_FUNCS [=[ # deprecated since dtk6 function(dconfig_meta_files) dtk_add_config_meta_files(${ARGV}) endfunction() function(dconfig_override_files) dtk_add_config_override_files(${ARGV}) endfunction()]=]) endif() configure_package_config_file(cmake/DtkDConfig/DtkDConfigConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkDConfig/Dtk${DTK_VERSION_MAJOR}DConfigConfig.cmake INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}DConfig" PATH_VARS TOOL_INSTALL_DIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkDConfig/Dtk${DTK_VERSION_MAJOR}DConfigConfig.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}DConfig") configure_package_config_file(misc/DtkCoreConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}Config.cmake INSTALL_DESTINATION ${CONFIG_CMAKE_INSTALL_DIR} PATH_VARS TOOL_INSTALL_DIR) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}ConfigVersion.cmake" VERSION ${DTK_VERSION} COMPATIBILITY SameMajorVersion ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}Config.cmake DESTINATION ${CONFIG_CMAKE_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}ConfigVersion.cmake DESTINATION ${CONFIG_CMAKE_INSTALL_DIR}) configure_file(misc/dtkcore.pc.in ${LIB_NAME}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") configure_file(misc/qt_lib_dtkcore.pri.in qt_lib_dtkcore.pri @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qt_lib_dtkcore.pri DESTINATION "${MKSPECS_INSTALL_DIR}") install(FILES misc/dtk_install_dconfig.prf DESTINATION ${FEATURES_INSTALL_DIR}) set(CONFIGNAME include/global/dtkcore_config.h) file(WRITE ${CONFIGNAME} "// it is auto make config\n" "#define DTK_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}\n" "#define DTK_VERSION_MINOR ${PROJECT_VERSION_MINOR}\n" "#define DTK_VERSION_PATCH ${PROJECT_VERSION_PATCH}\n" "#define DTK_VERSION_BUILD ${BUILD_VERSION}\n" "#define DTK_VERSION_STR \"${PROJECT_VERSION}\"\n" "\n" ) file(GLOB CONFIGSOURCE include/DtkCore/*) foreach(FILENAME ${CONFIGSOURCE}) get_filename_component(thefile ${FILENAME} NAME) file(APPEND ${CONFIGNAME} "#define DTKCORE_CLASS_${thefile}\n") endforeach() dtkcore-5.7.12/examples/000077500000000000000000000000001476226660600150765ustar00rootroot00000000000000dtkcore-5.7.12/examples/CMakeLists.txt000066400000000000000000000002131476226660600176320ustar00rootroot00000000000000add_subdirectory(expintf-example) add_subdirectory(textcodec-example) add_subdirectory(filewatcher-example) add_subdirectory(dlog-example) dtkcore-5.7.12/examples/dlog-example/000077500000000000000000000000001476226660600174545ustar00rootroot00000000000000dtkcore-5.7.12/examples/dlog-example/CMakeLists.txt000066400000000000000000000005201476226660600222110ustar00rootroot00000000000000set(BIN_NAME dlog${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) add_executable(${BIN_NAME} main.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core ${LIB_NAME} ) target_include_directories(${BIN_NAME} PUBLIC ../../include/ ) dtkcore-5.7.12/examples/dlog-example/main.cpp000066400000000000000000000016431476226660600211100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include DCORE_USE_NAMESPACE int main(int argc, char **argv) { QCoreApplication app(argc, argv); #ifdef Q_OS_LINUX DLogManager::registerJournalAppender(); #endif DLogManager::registerConsoleAppender(); dDebug() << "Anything that can possibly go wrong, will go wrong. "; qWarning() << "FBI Warning: Code smells."; qInfo() << "Why dark mode? Because light attracts bugs"; qCritical() << "You Should Never Run `sudo rm -rf /`"; { dDebugTime("Test the running time of a code block"); QTimer timer; timer.setInterval(500); QEventLoop loop; QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); timer.start(); loop.exec(); } return app.exec(); } dtkcore-5.7.12/examples/expintf-example/000077500000000000000000000000001476226660600202045ustar00rootroot00000000000000dtkcore-5.7.12/examples/expintf-example/CMakeLists.txt000066400000000000000000000006441476226660600227500ustar00rootroot00000000000000set(BIN_NAME exprintf${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus) add_executable(${BIN_NAME} main.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::DBus ${LIB_NAME} ) target_include_directories(${BIN_NAME} PUBLIC ../../include/base ../../include/base/private/ ../../include/filesystem/ ../../include/ ) dtkcore-5.7.12/examples/expintf-example/main.cpp000066400000000000000000000031341476226660600216350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "util/dexportedinterface.h" #include #include #include #include #include //#define ALTERNATE_USAGE DCORE_USE_NAMESPACE class CustomInterface : public DUtil::DExportedInterface { QVariant invoke(const QString &action, const QString ¶meters) const { QJsonDocument d = QJsonDocument::fromJson(parameters.toUtf8()); if (action == "pow") { return QVariant(pow(d["a"].toDouble(), d["b"].toDouble())); } return QVariant(); } }; int main(int argc, char **argv) { QCoreApplication app(argc, argv); QDBusConnection::sessionBus().registerService("com.deepin.ExpIntfTest"); #ifndef ALTERNATE_USAGE DUtil::DExportedInterface *ei = new DUtil::DExportedInterface(); ei->registerAction("quit", "quit the application", [&app](QString)->QVariant { app.quit(); return QVariant(); }); ei->registerAction("answer", "answer to the ultimate question of life, the universe, and everything", [](QString)->QVariant {return QVariant(42);}); ei->registerAction("sum", "returns the sum of two integers", [](QString p)->QVariant { QJsonDocument d = QJsonDocument::fromJson(p.toUtf8()); return QVariant(d["a"].toInt() + d["b"].toInt()); }); #else CustomInterface *cei = new CustomInterface(); cei->registerAction("pow", "raise a number to a power"); #endif return app.exec(); } dtkcore-5.7.12/examples/filewatcher-example/000077500000000000000000000000001476226660600210245ustar00rootroot00000000000000dtkcore-5.7.12/examples/filewatcher-example/CMakeLists.txt000066400000000000000000000005331476226660600235650ustar00rootroot00000000000000set(BIN_NAME filewatcher${DTK_VERSION_MAJOR}) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) add_executable(${BIN_NAME} main.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core ${LIB_NAME} ) target_include_directories(${BIN_NAME} PUBLIC ../../include/filesystem/ ../../include/ ) dtkcore-5.7.12/examples/filewatcher-example/main.cpp000066400000000000000000000025451476226660600224620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "filesystem/dfilewatchermanager.h" #include #include #include DCORE_USE_NAMESPACE int main(int argc, char **argv) { QCoreApplication app(argc, argv); DFileWatcherManager manager; QTemporaryFile tmpfile1; tmpfile1.open(); QFile file1(tmpfile1.fileName()); QTemporaryFile tmpfile2; tmpfile2.open(); QFile file2(tmpfile2.fileName()); manager.add(tmpfile1.fileName()); manager.add(tmpfile2.fileName()); QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileModified, &app, [=](const QString value) { qDebug() << "文件发生变动:" << value; }); QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileDeleted, &app, [=](const QString value) { qDebug() << "文件被删除:" << value; }); file1.open(QIODevice::WriteOnly | QIODevice::Text); file1.write("test"); file1.flush(); file1.close(); file2.open(QIODevice::WriteOnly | QIODevice::Text); file2.write("test"); file2.close(); qDebug() << manager.watchedFiles(); qDebug() << "---------------------------"; app.processEvents(); manager.removeAll(); qDebug() << manager.watchedFiles(); return app.exec(); } dtkcore-5.7.12/examples/textcodec-example/000077500000000000000000000000001476226660600205115ustar00rootroot00000000000000dtkcore-5.7.12/examples/textcodec-example/CMakeLists.txt000066400000000000000000000005231476226660600232510ustar00rootroot00000000000000set(BIN_NAME textcodec${DTK_VERSION_MAJOR}) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) add_executable(${BIN_NAME} main.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core ${LIB_NAME} ) target_include_directories(${BIN_NAME} PUBLIC ../../include/util/ ../../include/ ) dtkcore-5.7.12/examples/textcodec-example/main.cpp000066400000000000000000000075651476226660600221560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include DCORE_USE_NAMESPACE void convertFileEncoding(const QString &fromFile, const QString &toFile, const QByteArray &toEncoding, const QByteArray &fromEncoding = QByteArray()) { QByteArray contentEncoding = fromEncoding; if (contentEncoding.isEmpty()) { bool isOk = false; contentEncoding = DTextEncoding::detectFileEncoding(fromFile, &isOk); if (!isOk) { qInfo().noquote() << QString("Detect file %1 encoding failed").arg(fromFile); return; } } QString errString; if (!DTextEncoding::convertFileEncodingTo(fromFile, toFile, toEncoding, contentEncoding, &errString)) { qInfo().noquote() << QString("Convert file %1 encoding from %2 to %3 failed. error: %4") .arg(fromFile) .arg(QString::fromUtf8(contentEncoding)) .arg(QString::fromUtf8(toEncoding)) .arg(errString); } else { qInfo().noquote() << QString("Convert file %1 encoding from %2 to %3 successed.") .arg(fromFile) .arg(QString::fromUtf8(contentEncoding)) .arg(QString::fromUtf8(toEncoding)); } } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("Text codec"); QCommandLineOption toEncodingOption({"t", "toEncoding"}, "Convert file encoding to specified encoding.", "encoding"); QCommandLineOption fromEncodingOption({"f", "fromEncoding"}, "Convert file encoding from specified encoding.", "encoding"); QCommandLineOption outputOption( {"o", "output"}, "Save converted text with file path, only supported when opening a single file.", "path"); QCommandLineParser parser; parser.setApplicationDescription("Text codec, provide encoding detection and encoding conversion."); parser.addHelpOption(); parser.addOption(toEncodingOption); parser.addOption(fromEncodingOption); parser.addOption(outputOption); parser.addPositionalArgument("file", "Open file.", "[file...]"); parser.process(app); const QStringList args = parser.positionalArguments(); if (args.isEmpty()) { parser.showHelp(); } const QStringList fileArgs = parser.positionalArguments(); if (fileArgs.isEmpty()) { qInfo().noquote() << "Not set open file."; return 0; } if (parser.isSet(outputOption)) { if (fileArgs.size() > 1) { qInfo().noquote() << "Output file path only supported when opening a single file."; return 0; } else if (!parser.isSet(toEncodingOption)) { qInfo().noquote() << "Convert file with not set convert encoding."; } else { QString fromFile = fileArgs.first(); QString toFile = parser.value(outputOption); QByteArray toEncoding = parser.value(toEncodingOption).toUtf8(); convertFileEncoding(fromFile, toFile, toEncoding, parser.value(fromEncodingOption).toUtf8()); return 0; } } QByteArray toEncoding = parser.value(toEncodingOption).toUtf8(); for (QString fileName : fileArgs) { if (toEncoding.isEmpty()) { // Only display file encoding. qInfo().noquote() << fileName << DTextEncoding::detectFileEncoding(fileName); } else { // Convert file encoding. convertFileEncoding(fileName, fileName, toEncoding, parser.value(fromEncodingOption).toUtf8()); } } return 0; } dtkcore-5.7.12/include/000077500000000000000000000000001476226660600147035ustar00rootroot00000000000000dtkcore-5.7.12/include/DtkCore/000077500000000000000000000000001476226660600162365ustar00rootroot00000000000000dtkcore-5.7.12/include/DtkCore/DAbstractUnitFormatter000066400000000000000000000000441476226660600225520ustar00rootroot00000000000000#include "dabstractunitformatter.h" dtkcore-5.7.12/include/DtkCore/DBaseFileWatcher000066400000000000000000000000361476226660600212540ustar00rootroot00000000000000#include "dbasefilewatcher.h" dtkcore-5.7.12/include/DtkCore/DCapDir000066400000000000000000000000261476226660600174250ustar00rootroot00000000000000#include "dcapfile.h" dtkcore-5.7.12/include/DtkCore/DCapFile000066400000000000000000000000261476226660600175660ustar00rootroot00000000000000#include "dcapfile.h" dtkcore-5.7.12/include/DtkCore/DCapManager000066400000000000000000000000311476226660600202550ustar00rootroot00000000000000#include "dcapmanager.h" dtkcore-5.7.12/include/DtkCore/DConfig000066400000000000000000000000251476226660600174670ustar00rootroot00000000000000#include "dconfig.h" dtkcore-5.7.12/include/DtkCore/DConfigFile000066400000000000000000000000311476226660600202640ustar00rootroot00000000000000#include "dconfigfile.h" dtkcore-5.7.12/include/DtkCore/DDBusExtendedAbstractInterface000066400000000000000000000000541476226660600241070ustar00rootroot00000000000000#include "ddbusextendedabstractinterface.h" dtkcore-5.7.12/include/DtkCore/DDBusInterface000066400000000000000000000000341476226660600207400ustar00rootroot00000000000000#include "ddbusinterface.h" dtkcore-5.7.12/include/DtkCore/DDBusSender000066400000000000000000000000311476226660600202550ustar00rootroot00000000000000#include "ddbussender.h" dtkcore-5.7.12/include/DtkCore/DDciFile000066400000000000000000000000261476226660600175620ustar00rootroot00000000000000#include "ddcifile.h" dtkcore-5.7.12/include/DtkCore/DDesktopEntry000066400000000000000000000000331476226660600207140ustar00rootroot00000000000000#include "ddesktopentry.h" dtkcore-5.7.12/include/DtkCore/DDiskSizeFormatter000066400000000000000000000000401476226660600216700ustar00rootroot00000000000000#include "ddisksizeformatter.h" dtkcore-5.7.12/include/DtkCore/DError000066400000000000000000000000241476226660600173520ustar00rootroot00000000000000#include "derror.h" dtkcore-5.7.12/include/DtkCore/DExpected000066400000000000000000000000271476226660600200250ustar00rootroot00000000000000#include "dexpected.h" dtkcore-5.7.12/include/DtkCore/DExportedInterface000066400000000000000000000000401476226660600216720ustar00rootroot00000000000000#include "dexportedinterface.h" dtkcore-5.7.12/include/DtkCore/DFileServices000066400000000000000000000000331476226660600206440ustar00rootroot00000000000000#include "dfileservices.h" dtkcore-5.7.12/include/DtkCore/DFileSystemWatcher000066400000000000000000000000401476226660600216610ustar00rootroot00000000000000#include "dfilesystemwatcher.h" dtkcore-5.7.12/include/DtkCore/DFileWatcher000066400000000000000000000000321476226660600204550ustar00rootroot00000000000000#include "dfilewatcher.h" dtkcore-5.7.12/include/DtkCore/DFileWatcherManager000066400000000000000000000000411476226660600217500ustar00rootroot00000000000000#include "dfilewatchermanager.h" dtkcore-5.7.12/include/DtkCore/DLicenseInfo000066400000000000000000000000321476226660600204560ustar00rootroot00000000000000#include "dlicenseinfo.h" dtkcore-5.7.12/include/DtkCore/DLog000066400000000000000000000003731476226660600170110ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include dtkcore-5.7.12/include/DtkCore/DNotifySender000066400000000000000000000000331476226660600206720ustar00rootroot00000000000000#include "dnotifysender.h" dtkcore-5.7.12/include/DtkCore/DObject000066400000000000000000000000251476226660600174700ustar00rootroot00000000000000#include "dobject.h" dtkcore-5.7.12/include/DtkCore/DObjectPrivate000066400000000000000000000000271476226660600210250ustar00rootroot00000000000000#include "dobject_p.h" dtkcore-5.7.12/include/DtkCore/DPathBuf000066400000000000000000000000261476226660600176140ustar00rootroot00000000000000#include "dpathbuf.h" dtkcore-5.7.12/include/DtkCore/DPinyin000066400000000000000000000000251476226660600175300ustar00rootroot00000000000000#include "dpinyin.h" dtkcore-5.7.12/include/DtkCore/DRecentManager000066400000000000000000000000341476226660600207750ustar00rootroot00000000000000#include "drecentmanager.h" dtkcore-5.7.12/include/DtkCore/DSGApplication000066400000000000000000000000341476226660600207570ustar00rootroot00000000000000#include "dsgapplication.h" dtkcore-5.7.12/include/DtkCore/DSecureString000066400000000000000000000000331476226660600206760ustar00rootroot00000000000000#include "dsecurestring.h" dtkcore-5.7.12/include/DtkCore/DSettings000066400000000000000000000000271476226660600200640ustar00rootroot00000000000000#include "dsettings.h" dtkcore-5.7.12/include/DtkCore/DSettingsGroup000066400000000000000000000000341476226660600210770ustar00rootroot00000000000000#include "dsettingsgroup.h" dtkcore-5.7.12/include/DtkCore/DSettingsOption000066400000000000000000000000351476226660600212540ustar00rootroot00000000000000#include "dsettingsoption.h" dtkcore-5.7.12/include/DtkCore/DSingleton000066400000000000000000000000301476226660600202200ustar00rootroot00000000000000#include "dsingleton.h" dtkcore-5.7.12/include/DtkCore/DStandardPaths000066400000000000000000000000341476226660600210220ustar00rootroot00000000000000#include "dstandardpaths.h" dtkcore-5.7.12/include/DtkCore/DSysInfo000066400000000000000000000000261476226660600176550ustar00rootroot00000000000000#include "dsysinfo.h" dtkcore-5.7.12/include/DtkCore/DTextEncoding000066400000000000000000000000331476226660600206540ustar00rootroot00000000000000#include "dtextencoding.h" dtkcore-5.7.12/include/DtkCore/DThreadUtils000066400000000000000000000000321476226660600205100ustar00rootroot00000000000000#include "dthreadutils.h" dtkcore-5.7.12/include/DtkCore/DTimeUnitFormatter000066400000000000000000000000401476226660600217010ustar00rootroot00000000000000#include "dtimeunitformatter.h" dtkcore-5.7.12/include/DtkCore/DTrashManager000066400000000000000000000000331476226660600206350ustar00rootroot00000000000000#include "dtrashmanager.h" dtkcore-5.7.12/include/DtkCore/DUtil000066400000000000000000000000231476226660600171750ustar00rootroot00000000000000#include "dutil.h" dtkcore-5.7.12/include/DtkCore/DVtableHook000066400000000000000000000000311476226660600203150ustar00rootroot00000000000000#include "dvtablehook.h" dtkcore-5.7.12/include/DtkCore/DtkCores000066400000000000000000000022031476226660600176740ustar00rootroot00000000000000#ifndef DTK_CORE_MODULE_H #define DTK_CORE_MODULE_H #include "dtkcore_global.h" #include "dconfigfile.h" #include "dobject.h" #include "dsingleton.h" #include "dutil.h" #include "dpinyin.h" #include "dtimeunitformatter.h" #include "dabstractunitformatter.h" #include "ddisksizeformatter.h" #include "ddbussender.h" #include "drecentmanager.h" #include "dnotifysender.h" #include "dexportedinterface.h" #include "dvtablehook.h" #include "dfileservices.h" #include "dthreadutils.h" #include "dasync.h" #include "dtimedloop.h" #include "RollingFileAppender.h" #include "Logger.h" #include "FileAppender.h" #include "ConsoleAppender.h" #include "AbstractStringAppender.h" #include "AbstractAppender.h" #include "LogManager.h" #include "dbasefilewatcher.h" #include "dfilesystemwatcher.h" #include "dfilewatcher.h" #include "dfilewatchermanager.h" #include "dpathbuf.h" #include "dstandardpaths.h" #include "dtrashmanager.h" #include "gsettingsbackend.h" #include "qsettingbackend.h" #include "dsettings.h" #include "dsettingsoption.h" #include "dsettingsgroup.h" #include "dsettingsbackend.h" #include "dsettingsdconfigbackend.h" #include "ddcifile.h" #endif dtkcore-5.7.12/include/base/000077500000000000000000000000001476226660600156155ustar00rootroot00000000000000dtkcore-5.7.12/include/base/derror.h000066400000000000000000000063401476226660600172660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DERROR_H #define DERROR_H #include "dtkcore_global.h" #include #include DCORE_BEGIN_NAMESPACE /** * @brief 对于错误的包装类 */ class DError { public: /*! * @brief 默认构造函数 * @attention 错误代码默认为-1,错误信息默认为空 */ DError() noexcept : m_code(-1) , m_msg() { } /*! * @brief 拷贝构造函数 */ DError(const DError &e) noexcept : m_code(e.m_code) , m_msg(e.m_msg) { } /*! * @brief 移动构造函数 * @attention 移动后原对象不可用 */ DError(DError &&e) noexcept : m_code(e.m_code) , m_msg(std::move(e).m_msg) { } /*! * @brief 构造函数 * @param[in] code 错误代码 * @param[in] msg 错误信息 */ DError(qint64 code, const QString &msg) noexcept : m_code(code) , m_msg(msg) { } /*! * @brief 构造函数 * @param[in] code 错误代码 * @param[in] msg 错误信息 * @attention 使用此构造函数后原错误信息不可用 */ DError(qint64 code, QString &&msg) noexcept : m_code(code) , m_msg(std::move(msg)) { } /*! * @brief 重载拷贝赋值运算符 */ DError &operator=(const DError &e) { m_code = e.m_code; m_msg = e.m_msg; return *this; } /*! * @brief 重载移动赋值运算符 * @attention 赋值后原对象不可用 */ DError &operator=(DError &&e) { m_code = e.m_code; m_msg = std::move(e).m_msg; return *this; } /*! * @brief 默认析构函数 */ ~DError() = default; /*! * @brief 获取错误代码 * @return 错误代码 */ qint64 getErrorCode() const noexcept { return m_code; } /*! * @brief 设置错误代码 * @param[in] code 错误代码 */ void setErrorCode(qint64 code) &noexcept { m_code = code; } /*! * @brief 获取错误信息 * @return 错误信息的const引用 */ const QString &getErrorMessage() const & { return m_msg; } /*! * @brief 获取错误信息 * @attention 函数返回错误信息后,原信息不可用 * @return 错误信息 */ QString getErrorMessage() const && { return std::move(m_msg); } /*! * @brief 设置错误信息 * @param[in] msg 错误信息 */ void setErrorMessage(const QString &msg) & { m_msg = msg; } /*! * @brief 重载相等运算符 */ friend bool operator==(const DError &x, const DError &y) noexcept { return x.m_code == y.m_code and x.m_msg == y.m_msg; } /*! * @brief 重载不等运算符 */ friend bool operator!=(const DError &x, const DError &y) noexcept { return !(x == y); } /*! * @brief 重载输出运算符 */ friend QDebug operator<<(QDebug debug, const DError &e) { debug << "Error Code:" << e.m_code << "Message:" << e.m_msg; return debug; } private: qint64 m_code; QString m_msg; }; DCORE_END_NAMESPACE #endif dtkcore-5.7.12/include/base/dexpected.h000066400000000000000000001534201476226660600177400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DEXPECTED_H #define DEXPECTED_H #include #include #include #include #include #include #include "derror.h" DCORE_BEGIN_NAMESPACE #define likely(x) __builtin_expect(static_cast((x)), 1) #define unlikely(x) __builtin_expect(reinterpret_cast((x)), 0) #if __cpp_exceptions #define _DEXPECTED_THROW_OR_ABORT(_EXC) (throw(_EXC)) #else #define _DEXPECTED_THROW_OR_ABORT(_EXC) (std::abort()) #endif template class DExpected; template class DUnexpected; template using _bool_constant = std::integral_constant; /*! * @brief 原位构造标签 */ enum class emplace_tag { USE_EMPLACE /**< 使用原位构造 */ }; /*! * @brief 从DUnexpected构造标签 */ enum class dunexpected_tag { DUNEXPECTED /**< 从DUnexpected构造 */ }; template struct remove_cvref { using type = typename std::remove_cv::type>::type; }; template class bad_result_access; template <> class bad_result_access : public std::exception { protected: bad_result_access() noexcept {} bad_result_access(const bad_result_access &) = default; bad_result_access(bad_result_access &&) = default; bad_result_access &operator=(const bad_result_access &) = default; bad_result_access &operator=(bad_result_access &&) = default; ~bad_result_access() = default; public: const char *what() const noexcept override { return "bad access to DExpected without value"; } }; template class bad_result_access : public bad_result_access { public: explicit bad_result_access(E _e) : m_error(std::move(_e)) { } E &error() &noexcept { return m_error; } const E &error() const &noexcept { return m_error; } E error() &&noexcept { return std::move(m_error); } const E error() const &&noexcept { return std::move(m_error); } private: E m_error; }; template auto construct_at(Type *p, Args &&...args) noexcept(noexcept(::new((void *)0) Type(std::declval()...))) -> decltype(::new((void *)0) Type(std::declval()...)) { return ::new ((void *)p) Type(std::forward(args)...); } namespace __dexpected { template void destroy_at_obj(ObjType *p) { p->~ObjType(); } template void destroy_at_arr(ArrType *p) { for (auto &elem : *p) destroy_at_obj(std::addressof(elem)); } } // namespace __dexpected template ::value, bool>::type = true> void destroy_at(Type *p) { __dexpected::destroy_at_arr(p); } template ::value, bool>::type = true> void destroy_at(Type *p) { __dexpected::destroy_at_obj(p); } namespace __dexpected { template struct Guard { static_assert(std::is_nothrow_move_constructible::value, "type T must bu nothrow_move_constructible"); explicit Guard(T &_x) : m_guarded(std::addressof(_x)) , m_tmp(std::move(_x)) { destroy_at(m_guarded); } ~Guard() { if (unlikely(m_guarded)) { construct_at(m_guarded, std::move(m_tmp)); } } Guard(const Guard &) = delete; Guard &operator=(const Guard &) = delete; T &&release() noexcept { return std::move(m_tmp); } private: T *m_guarded; T m_tmp; }; } // namespace __dexpected namespace __dexpected { template struct _is_dexpected : public std::false_type { }; template struct _is_dexpected> : public std::true_type { }; template struct _is_dunexpected : public std::false_type { }; template struct _is_dunexpected> : public std::true_type { }; template constexpr bool _can_be_dunexpected() { return std::is_object::value and !std::is_array::value and !_is_dunexpected() and !std::is_const::value and !std::is_volatile::value; } template ::value and std::is_nothrow_move_constructible::value, bool>::type = true> void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible::value) { destroy_at(_oldVal); construct_at(_newVal, std::forward(_arg)); } template ::value and !std::is_nothrow_move_constructible::value, bool>::type = true> void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible::value) { destroy_at(_oldVal); construct_at(_newVal, std::forward(_arg)); } template ::value and std::is_nothrow_move_constructible::value, bool>::type = true> void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible::value) { Tp _tmp(std::forward(_arg)); destroy_at(_oldVal); construct_at(_newVal, std::move(_tmp)); } template < typename Tp, typename Up, typename Vp, typename std::enable_if::value and !std::is_nothrow_move_constructible::value, bool>::type = true> void reinit(Tp *_newVal, Up *_oldVal, Vp &&_arg) noexcept(std::is_nothrow_constructible::value) { __dexpected::Guard _guard(*_oldVal); construct_at(_newVal, std::forward(_arg)); _guard.release(); } } // namespace __dexpected /*! * @brief * 类模板Dtk::Core::DUnexpected代表一个Dtk::Core::DExpected中存储的不期待的值 * @tparam E * 不期待的值的类型,该类型不能是非对象类型,数组类型,Dtk::Core::DUnexpected的特化类型或有cv限定符的类型 */ template class DUnexpected { static_assert(__dexpected::_can_be_dunexpected(), "can't be dunexpected"); public: /*! * @brief Dtk::Core::DUnexpected的默认拷贝构造函数 */ constexpr DUnexpected(const DUnexpected &) = default; /*! * @brief Dtk::Core::DUnexpected的默认移动构造函数 */ constexpr DUnexpected(DUnexpected &&) = default; /*! * @brief 使用类型E直接初始化一个Dtk::Core::DUnexpected对象 * @tparam Er 错误类型,默认为E * @param[in] _e 一个类型为Er的值 */ template ::type, DUnexpected>::value and !std::is_same::type, emplace_tag>::value and std::is_constructible::value, bool>::type = true> constexpr explicit DUnexpected(Er &&_e) noexcept(std::is_nothrow_constructible::value) : m_error(std::forward(_e)) { } /*! * @brief * 直接从参数构造出一个包含错误类型为E的对象的Dtk::Core::DUnexpected对象 * @tparam Args 可变参数模板类型,这里是构造类型为E的对象所需要的参数的类型 * @param[in] args 构造类型为E的对象用到的参数 * @attention * 为了区分是构造E还是Dtk::Core::DUnexpected,需要在第一个参数使用emplace_tag进行标识 */ template constexpr explicit DUnexpected(emplace_tag, Args &&...args) noexcept(std::is_nothrow_constructible::value) : m_error(std::forward(args)...) { static_assert(std::is_constructible::value, "can't construct E from args."); } /*! * @brief * 从参数和初始化列表构造出一个包含错误类型为E的对象的Dtk::Core::DUnexpected对象 * @tparam U 初始化列表的模板类型 * @tparam Args 可变参数模板类型,这里是构造类型为E的对象所需要的参数的类型 * @param _li 模板类型为U的初始化列表 * @param[in] args 构造类型为E的对象用到的参数 * @attention * 为了区分是构造E还是Dtk::Core::DUnexpected,需要在第一个参数使用emplace_tag进行标识 */ template constexpr explicit DUnexpected(emplace_tag, std::initializer_list _li, Args &&...args) noexcept( std::is_nothrow_constructible &, Args...>::value) : m_error(_li, std::forward(args)...) { } /*! * @brief Dtk::Core::DUnexpected的默认拷贝赋值运算符 */ DUnexpected &operator=(const DUnexpected &) = default; /*! * @brief Dtk::Core::DUnexpected的默认移动赋值运算符 */ DUnexpected &operator=(DUnexpected &&) = default; /*! * @brief 获取Dtk::Core::DUnexpected持有的不期待值 * @return 不期待值的const左值引用 */ constexpr const E &error() const &noexcept { return m_error; } /*! * @brief 获取Dtk::Core::DUnexpected持有的不期待值 * @return 不期待值的左值引用 */ E &error() &noexcept { return m_error; } /*! * @brief 获取Dtk::Core::DUnexpected持有的不期待值 * @attention 获取后原Dtk::Core::DUnexpected不可用 * @return 不期待值的const右值引用 */ constexpr const E &&error() const &&noexcept { return std::move(m_error); } /*! * @brief 获取Dtk::Core::DUnexpected持有的不期待值 * @attention 获取后原Dtk::Core::DUnexpected不可用 * @return 不期待值的右值引用 */ E &&error() &&noexcept { return std::move(m_error); } /*! * @brief 交换两个Dtk::Core::DUnexpected的值 * @param[in] _other 另一个模板参数为E的Dtk::Core::DUnexpected对象 */ void swap(DUnexpected &_other) { using std::swap; swap(m_error, _other.m_error); } /*! * @brief 重载相等运算符 * @tparam Er 另一个Dtk::Core::DUnexpected的模板类型 * @param[in] _x 模板参数为E的Dtk::Core::DUnexpected对象 * @param[in] _y 模板参数为Er的Dtk::Core::DUnexpected对象 */ template friend constexpr bool operator==(const DUnexpected &_x, const DUnexpected _y) { return _x.m_error == _y.error(); } /*! * @brief 交换两个Dtk::Core::DUnexpected的值 */ friend void swap(DUnexpected &_x, DUnexpected &_y) { _x.swap(_y); } private: E m_error; }; /*! * @brief * 模板类Dtk::Core::DExpected提供存储两个值之一的方式。Dtk::Core::DExpected的对象要么保有一个期待的T类型值,要么保有一个不期待的E类型值,不会没有值。 * @tparam T 期待的类型 * @tparam E 不期待的类型 * @note 该类自DtkCore 5.6.3引入 */ template class DExpected { template friend class DExpected; static_assert(!std::is_reference::value, "type T can't be reference type"); static_assert(!std::is_function::value, "type T can't be function type"); static_assert(!std::is_same::type, dunexpected_tag>::value, "type T can't be dunexpected_tag"); static_assert(!std::is_same::type, emplace_tag>::value, "type T can't be emplace_tag"); static_assert(!__dexpected::_is_dunexpected::type>::value, "type T can't be DUnexpected"); static_assert(__dexpected::_can_be_dunexpected(), "type E can't be dunexpected"); template > static constexpr bool __cons_from_DExpected() { return std::is_constructible &>::value or std::is_constructible>::value or std::is_constructible>::value or std::is_constructible &>::value or std::is_convertible &, T>::value or std::is_convertible, T>::value or std::is_convertible &, T>::value or std::is_convertible, T>::value or std::is_constructible &>::value or std::is_constructible>::value or std::is_constructible &>::value or std::is_constructible>::value; } template static constexpr bool __explicit_conv() { return !std::is_convertible::value or !std::is_convertible::value; } static constexpr bool des_value() { return !std::is_trivially_destructible::value or !std::is_trivially_destructible::value; } template void assign_val(V &&_v) { if (m_has_value) { m_value = std::forward(_v); } else { __dexpected::reinit(std::addressof(m_value), std::addressof(m_error), std::forward(_v)); m_has_value = true; } } template void assign_err(V &&_v) { if (m_has_value) { __dexpected::reinit(std::addressof(m_error), std::addressof(m_value), std::forward(_v)); m_has_value = false; } else { m_error = std::forward(_v); } } template ::value, bool>::type = true> void swap_val_err(DExpected &_other) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_constructible::value) { __dexpected::Guard _guard(_other.m_error); construct_at(std::addressof(_other.m_value), std::move(m_value)); _other.m_has_value = true; destroy_at(std::addressof(m_value)); construct_at(std::addressof(m_error), _guard.release()); m_has_value = false; } template ::value, bool>::type = true> void swap_val_err(DExpected &_other) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_constructible::value) { __dexpected::Guard _guard(_other.m_value); construct_at(std::addressof(m_error), std::move(_other.m_error)); m_has_value = false; destroy_at(std::addressof(_other.m_error)); construct_at(std::addressof(_other.m_value), _guard.release()); _other.m_has_value = true; } public: using value_type = T; using error_type = E; using dunexpected_type = DUnexpected; template using rebind = DExpected; /*! * @brief Dtk::Core::DExpected的默认构造函数 */ template ::value, bool>::type = true> constexpr DExpected() noexcept(std::is_nothrow_default_constructible::value) : m_has_value(true) , m_value() { } /*! * @brief Dtk::Core::DExpected的拷贝构造函数 */ template < typename std::enable_if::value and std::is_copy_constructible::value, bool>::type = true> DExpected(const DExpected &_x) noexcept( std::is_nothrow_copy_constructible::value and std::is_nothrow_copy_constructible::value) : m_has_value(_x.m_has_value) { if (m_has_value) construct_at(std::addressof(m_value), _x.m_value); else construct_at(std::addressof(m_error), _x.m_error); } /*! * @brief Dtk::Core::DExpected的移动构造函数 */ template < typename std::enable_if::value and std::is_move_constructible::value, bool>::type = true> DExpected(DExpected &&_x) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_constructible::value) : m_has_value(_x.m_has_value) { if (m_has_value) construct_at(std::addressof(m_value), std::move(_x).m_value); else construct_at(std::addressof(m_error), std::move(_x).m_error); } /*! * @brief Dtk::Core::DExpected的拷贝构造函数 * @tparam U 另一个Dtk::Core::DExpected的期待类型 * @tparam G 另一个Dtk::Core::DExpected的不期待类型 * @param[in] _x 模板类型分别为U和G的Dtk::Core::DExpected对象 */ template < typename U, typename G, typename std::enable_if::value and std::is_constructible::value and !__cons_from_DExpected() and !__explicit_conv(), bool>::type = true> DExpected(const DExpected &_x) noexcept( std::is_nothrow_constructible::value and std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) { if (m_has_value) construct_at(std::addressof(m_value), _x.m_value); else construct_at(std::addressof(m_error), _x.m_error); } /*! * @brief Dtk::Core::DExpected的拷贝构造函数 * @tparam U 另一个Dtk::Core::DExpected的期待类型 * @tparam G 另一个Dtk::Core::DExpected的不期待类型 * @param[in] _x 模板类型分别为U和G的Dtk::Core::DExpected对象 * @attention 该拷贝构造函数有explicit标识 */ template < typename U, typename G, typename std::enable_if::value and std::is_constructible::value and !__cons_from_DExpected() and __explicit_conv(), bool>::type = true> explicit DExpected(const DExpected &_x) noexcept( std::is_nothrow_constructible::value and std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) { if (m_has_value) construct_at(std::addressof(m_value), _x.m_value); else construct_at(std::addressof(m_error), _x.m_error); } /*! * @brief Dtk::Core::DExpected的移动构造函数 * @tparam U 另一个Dtk::Core::DExpected的期待类型 * @tparam G 另一个Dtk::Core::DExpected的不期待类型 * @param[in] _x 模板类型分别为U和G的Dtk::Core::DExpected对象 * @attention 构造后另一个Dtk::Core::DExpected不可用 */ template ::value and std::is_constructible::value and !__cons_from_DExpected() and !__explicit_conv(), bool>::type = true> DExpected(DExpected &&_x) noexcept( std::is_nothrow_constructible::value and std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) { if (m_has_value) construct_at(std::addressof(m_value), std::move(_x).m_value); else construct_at(std::addressof(m_error), std::move(_x).m_error); } /*! * @brief Dtk::Core::DExpected的移动构造函数 * @tparam U 另一个Dtk::Core::DExpected的期待类型 * @tparam G 另一个Dtk::Core::DExpected的不期待类型 * @param[in] _x 模板类型分别为U和G的Dtk::Core::DExpected对象 * @attention 构造后另一个Dtk::Core::DExpected不可用,该函数有explicit标识 */ template ::value and std::is_constructible::value and !__cons_from_DExpected() and __explicit_conv(), bool>::type = true> explicit DExpected(DExpected &&_x) noexcept( std::is_nothrow_constructible::value and std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) { if (m_has_value) construct_at(std::addressof(m_value), std::move(_x).m_value); else construct_at(std::addressof(m_error), std::move(_x).m_error); } /*! * @brief * Dtk::Core::DExpected的移动构造函数,直接从期待类型构造出Dtk::Core::DExpected对象 * @tparam U Dtk::Core::DExpected的期待类型,默认为类型T * @param[in] _v 期待类型为U的对象 * @attention 构造后原对象不可用,该函数有explicit标识 */ template ::type, DExpected>::value and !std::is_same::type, emplace_tag>::value and !__dexpected::_is_dunexpected::type>::value and std::is_constructible::value and !std::is_convertible::value, bool>::type = true> constexpr explicit DExpected(U &&_v) noexcept(std::is_nothrow_constructible::value) : m_has_value(true) , m_value(std::forward(_v)) { } /*! * @brief * Dtk::Core::DExpected的移动构造函数,直接从期待类型构造出Dtk::Core::DExpected对象 * @tparam U Dtk::Core::DExpected的期待类型,默认为类型T * @param[in] _v 期待类型为U的对象 * @attention 构造后原对象不可用 */ template ::type, DExpected>::value and !std::is_same::type, emplace_tag>::value and !__dexpected::_is_dunexpected::type>::value and std::is_constructible::value and std::is_convertible::value, bool>::type = true> constexpr DExpected(U &&_v) noexcept(std::is_nothrow_constructible::value) : m_has_value(true) , m_value(std::forward(_v)) { } /*! * @brief * Dtk::Core::DExpected的拷贝构造函数,从Dtk::Core::DUnexpected构造出Dtk::Core::DExpected对象 * @tparam G Dtk::Core::DExpected的期待类型,默认为类型E * @param[in] _u 期待类型为G的Dtk::Core::DUnexpected对象 * @attention 该函数有explicit标识 */ template ::value and !std::is_convertible::value, bool>::type = true> constexpr explicit DExpected(const DUnexpected &_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(_u.error()) { } /*! * @brief * Dtk::Core::DExpected的拷贝构造函数,从Dtk::Core::DUnexpected构造出Dtk::Core::DExpected对象 * @tparam G Dtk::Core::DExpected的期待类型,默认为类型E * @param[in] _u 期待类型为G的Dtk::Core::DUnexpected对象 */ template ::value and std::is_convertible::value, bool>::type = true> constexpr DExpected(const DUnexpected &_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(_u.error()) { } /*! * @brief * Dtk::Core::DExpected的移动构造函数,从Dtk::Core::DUnexpected构造出Dtk::Core::DExpected对象 * @tparam G Dtk::Core::DExpected的期待类型,默认为类型E * @param[in] _u 期待类型为G的Dtk::Core::DUnexpected对象 * @attention 构造后原对象不可用,该函数有explicit标识 */ template < typename G = E, typename std::enable_if::value and !std::is_convertible::value, bool>::type = true> constexpr explicit DExpected(DUnexpected &&_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(std::move(_u).error()) { } /*! * @brief * Dtk::Core::DExpected的移动构造函数,从Dtk::Core::DUnexpected构造出Dtk::Core::DExpected对象 * @tparam G Dtk::Core::DExpected的期待类型,默认为类型E * @param[in] _u 期待类型为G的Dtk::Core::DUnexpected对象 * @attention 构造后原对象不可用 */ template ::value and std::is_convertible::value, bool>::type = true> constexpr DExpected(DUnexpected &&_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(std::move(_u).error()) { } /*! * @brief Dtk::Core::DExpected的转发构造函数,从参数直接构造出期待值 * @tparam Args 构造期待类型T所用到的参数的类型 * @param[in] args 构造期待类型T所用到的参数 * @attention * 为了区分是构造T还是Dtk::Core::DExpected,需要在第一个参数使用emplace_tag进行标识 */ template constexpr explicit DExpected(emplace_tag, Args &&...args) noexcept(std::is_nothrow_constructible::value) : m_has_value(true) , m_value(std::forward(args)...) { static_assert(std::is_constructible::value, "can't construct T from args."); } /*! * @brief Dtk::Core::DExpected的转发构造函数,从参数直接构造出期待值 * @tparam U 初始化列表的模板参数 * @tparam Args 构造期待类型T所用到的参数的类型 * @param[in] _li 构造期待类型T所用到的初始化列表 * @param[in] args 构造期待类型T所用到的参数 * @attention * 为了区分是构造T还是Dtk::Core::DExpected,需要在第一个参数使用emplace_tag进行标识 */ template constexpr explicit DExpected(emplace_tag, std::initializer_list _li, Args &&...args) noexcept( std::is_nothrow_constructible &, Args...>::value) : m_has_value(true) , m_value(_li, std::forward(args)...) { static_assert(std::is_constructible &, Args...>::value, "can't construct T from args."); } /*! * @brief Dtk::Core::DExpected的转发构造函数,从参数直接构造出不期待值 * @tparam Args 构造不期待类型E所用到的参数的类型 * @param[in] args 构造不期待类型E所用到的参数 * @attention * 为了区分是构造E还是Dtk::Core::DExpected,需要在第一个参数使用dunexpected_tag进行标识 */ template constexpr explicit DExpected(dunexpected_tag, Args &&...args) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(std::forward(args)...) { static_assert(std::is_constructible::value, "can't construct E from args."); } /*! * @brief Dtk::Core::DExpected的转发构造函数,从参数直接构造出不期待值 * @tparam U 初始化列表的模板参数 * @tparam Args 构造不期待类型E所用到的参数的类型 * @param[in] _li 构造不期待类型E所用到的初始化列表 * @param[in] args 构造不期待类型E所用到的参数 * @attention * 为了区分是构造E还是Dtk::Core::DExpected,需要在第一个参数使用dunexpected_tag进行标识 */ template constexpr explicit DExpected(dunexpected_tag, std::initializer_list _li, Args &&...args) noexcept( std::is_nothrow_constructible &, Args...>::value) : m_has_value(false) , m_error(_li, std::forward(args)...) { static_assert(std::is_constructible &, Args...>::value, "can't construct E from args."); } /*! * @brief Dtk::Core::DExpected的析构函数 */ ~DExpected() { if (des_value()) { if (m_has_value) { destroy_at(std::addressof(m_value)); } else { destroy_at(std::addressof(m_error)); } } } /*! * @brief Dtk::Core::DExpected的默认拷贝赋值运算符 */ DExpected &operator=(const DExpected &) = delete; /*! * @brief Dtk::Core::DExpected的拷贝赋值运算符 * @param[in] _x 同类型的Dtk::Core::DExpected对象 */ template ::value and std::is_copy_constructible::value and std::is_copy_assignable::value and std::is_copy_constructible::value and (std::is_nothrow_move_constructible::value or std::is_nothrow_move_constructible::value), bool>::type = true> DExpected &operator=(const DExpected &_x) noexcept( std::is_nothrow_copy_constructible::value and std::is_nothrow_copy_constructible::value and std::is_nothrow_copy_assignable::value and std::is_nothrow_copy_assignable::value) { if (_x.m_has_value) this->assign_val(_x.m_value); else this->assign_err(_x.m_error); return *this; } /*! * @brief Dtk::Core::DExpected的移动赋值运算符 * @param[in] _x 同类型的Dtk::Core::DExpected对象 * @attention 赋值后原对象不可用 */ template ::value and std::is_move_constructible::value and std::is_move_assignable::value and std::is_move_constructible::value and (std::is_nothrow_move_constructible::value or std::is_nothrow_move_constructible::value), bool>::type = true> DExpected &operator=(DExpected &&_x) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_assignable::value) { if (_x.m_has_value) assign_val(std::move(_x.m_value)); else assign_err(std::move(_x.m_error)); return *this; } /*! * @brief Dtk::Core::DExpected的转发赋值运算符 * @tparam U 期待类型,默认为T * @param[in] _v 期待类型U的对象 */ template < typename U = T, typename std::enable_if::type>::value and !__dexpected::_is_dunexpected::type>::value and std::is_constructible::value and std::is_assignable::value and (std::is_nothrow_constructible::value or std::is_nothrow_move_constructible::value or std::is_nothrow_move_constructible::value), bool>::type = true> DExpected &operator=(U &&_v) { assign_val(std::forward(_v)); return *this; } /*! * @brief Dtk::Core::DExpected的拷贝赋值运算符 * @tparam G 不期待类型 * @param[in] _e 模板类型为G的Dtk::Core::DUnexpected对象 */ template ::value and std::is_assignable::value and (std::is_nothrow_constructible::value or std::is_nothrow_move_constructible::value or std::is_move_constructible::value), bool>::type = true> DExpected &operator=(const DUnexpected &_e) { assign_err(_e.error()); return *this; } /*! * @brief Dtk::Core::DExpected的移动赋值运算符 * @tparam G 不期待类型 * @param[in] _e 模板类型为G的Dtk::Core::DUnexpected对象 * @attention 赋值后原对象不可用 */ template ::value and std::is_assignable::value and (std::is_nothrow_constructible::value or std::is_nothrow_move_constructible::value or std::is_move_constructible::value), bool>::type = true> DExpected &operator=(DUnexpected &&_e) { assign_err(std::move(_e).error()); return *this; } /*! * @brief 从参数直接转发构造期待值 * @tparam Args 构造期待值所用到的参数的类型 * @param[in] args 构造期待值所用到的参数 * @return 返回构造好的期待值的引用 */ template T &emplace(Args &&...args) noexcept { static_assert(std::is_nothrow_constructible::value, "type T should have nothrow_constructible"); if (m_has_value) destroy_at(std::addressof(m_value)); else { destroy_at(std::addressof(m_error)); m_has_value = true; } construct_at(std::addressof(m_value), std::forward(args)...); return m_value; } /*! * @brief 从参数直接转发构造期待值 * @tparam U 初始化列表的模板参数 * @tparam Args 构造期待值所用到的参数的类型 * @param[in] args 构造期待值所用到的参数 * @param[in] li 构造期待值所用到的参数化列表 * @return 返回构造好的期待值的引用 */ template T &emplace(std::initializer_list li, Args &&...args) noexcept { static_assert(std::is_nothrow_constructible &, Args...>::value, "type T should have a noexcept constructor"); if (m_has_value) destroy_at(std::addressof(m_value)); else { destroy_at(std::addressof(m_error)); } construct_at(std::addressof(m_value), li, std::forward(args)...); return m_value; } // TODO:需要swap吗? /*! * @brief 交换两个Dtk::Core::DExpected的值 * @param[in] _x 另一个Dtk::Core::DExpected对象 */ template ::value and std::is_move_constructible::value and (std::is_nothrow_move_constructible::value or std::is_nothrow_move_constructible::value), bool>::type = true> void swap(DExpected &_x) noexcept(std::is_nothrow_move_constructible::value and std::is_nothrow_move_constructible::value) { if (m_has_value) { if (_x.m_has_value) { using std::swap; swap(m_value, _x.m_value); } else { this->swap_val_err(_x); } } else { if (_x.m_has_value) _x.swap_val_err(*this); else { using std::swap; swap(m_error, _x.m_error); } } } /*! * @brief 重载箭头运算符 * @return 一个指向期待值的const指针 */ const T *operator->() const noexcept { assert(m_has_value); return std::addressof(m_value); } /*! * @brief 重载箭头运算符 * @return 一个指向期待值的指针 */ T *operator->() noexcept { assert(m_has_value); return std::addressof(m_value); } /*! * @brief 重载解引用运算符 * @return 一个期待值的const左值引用 */ const T &operator*() const &noexcept { assert(m_has_value); return m_value; } /*! * @brief 重载解引用运算符 * @return 一个期待值的左值引用 */ T &operator*() &noexcept { assert(m_has_value); return m_value; } /*! * @brief 重载解引用运算符 * @return 一个期待值的const右值引用 */ const T &&operator*() const &&noexcept { assert(m_has_value); return std::move(m_value); } /*! * @brief 重载解引用运算符 * @return 一个期待值的右值引用 */ T &&operator*() &&noexcept { assert(m_has_value); return std::move(m_value); } /*! * @brief bool转换函数 * @return 表示Dtk::Core::DExpected是否有值的bool值 */ constexpr explicit operator bool() const noexcept { return m_has_value; } /*! * @brief 判断Dtk::Core::DExpected是否有值 * @return 表示是否有值的bool值 */ constexpr bool hasValue() const noexcept { return m_has_value; } /*! * @brief 获取Dtk::Core::DExpected的期待值 * @return 期待值的const左值引用 */ const T &value() const & { if (likely(m_has_value)) { return m_value; } _DEXPECTED_THROW_OR_ABORT(bad_result_access(m_error)); } /*! * @brief 获取Dtk::Core::DExpected的期待值 * @return 期待值的左值引用 */ T &value() & { if (likely(m_has_value)) { return m_value; } _DEXPECTED_THROW_OR_ABORT(bad_result_access(m_error)); } /*! * @brief 获取Dtk::Core::DExpected的期待值 * @return 期待值的const右值引用 * @attention 调用后期待值不可用 */ const T &&value() const && { if (likely(m_has_value)) { return std::move(m_value); } _DEXPECTED_THROW_OR_ABORT(bad_result_access(m_error)); } /*! * @brief 获取Dtk::Core::DExpected的期待值 * @return 期待值的右值引用 * @attention 调用后期待值不可用 */ T &&value() && { if (likely(m_has_value)) { return std::move(m_value); } _DEXPECTED_THROW_OR_ABORT(bad_result_access(m_error)); } /*! * @brief 获取Dtk::Core::DExpected的不期待值 * @return 不期待值的const左值引用 */ const E &error() const &noexcept { assert(!m_has_value); return m_error; } /*! * @brief 获取Dtk::Core::DExpected的不期待值 * @return 不期待值的左值引用 */ E &error() &noexcept { assert(!m_has_value); return m_error; } /*! * @brief 获取Dtk::Core::DExpected的不期待值 * @return 不期待值的const右值引用 * @attention 调用后不期待值不可用 */ const E &&error() const &&noexcept { assert(!m_has_value); return std::move(m_error); } /*! * @brief 获取Dtk::Core::DExpected的不期待值 * @return 不期待值的右值引用 * @attention 调用后不期待值不可用 */ E &&error() &&noexcept { assert(!m_has_value); return std::move(m_error); } // TODO:因为无法确定U转T时是否会抛出异常,所以都按抛出异常来 /*! * @brief 如果有期待值返回期待值,否则返回传入的默认值 * @tparam U 期待值的类型 * @param[in] _v 默认的期待值 * @return 期待值 */ template T value_or(U &&_v) const & { static_assert(std::is_copy_constructible::value, "type T should have an copy constructor."); static_assert(std::is_convertible::value, "type U must can be converted to T."); if (m_has_value) return m_value; return static_cast(std::forward(_v)); } /*! * @brief 如果有期待值返回期待值,否则返回传入的默认值 * @tparam U 期待值的类型 * @param[in] _v 默认的期待值 * @return 期待值 * @attention 如果由期待值,调用后原期待值不可用,同时类型U要可以转换成类型T */ template T value_or(U &&_v) && { static_assert(std::is_move_constructible::value, "type T must bu copy_constructible."); static_assert(std::is_convertible::value, "type U must can be converted to T."); if (m_has_value) return std::move(m_value); return static_cast(std::forward(_v)); } /*! *@brief 重载相等运算符 */ template ::value, bool>::type = true> friend bool operator==(const DExpected &_x, const DExpected &_y) noexcept(noexcept(bool(*_x == *_y)) and noexcept(bool(_x.error() == _y.error()))) { if (_x.hasValue()) return _y.hasValue() and bool(*_x == *_y); else return !_y.hasValue() and bool(_x.error() == _x.error()); } /*! *@brief 重载相等运算符 */ template friend constexpr bool operator==(const DExpected &_x, const U &_v) noexcept(noexcept(bool(*_x == _v))) { return _x.hasValue() && bool(*_x == _v); } /*! *@brief 重载相等运算符 */ template friend constexpr bool operator==(const DExpected &_x, const DUnexpected &_e) noexcept(noexcept(bool(_x.error() == _e.error()))) { return !_x.hasValue() && bool(_x.error() == _e.error()); } /*! *@brief 交换两个Dtk::Core::DExpected中的值 */ friend void swap(DExpected &_x, DExpected &_y) noexcept(noexcept(_x.swap(_y))) { _x.swap(_y); } private: bool m_has_value; union { T m_value; E m_error; }; }; /*! * @brief 对于Dtk::Core::DExpected的void偏特化,其他函数参考原模板类 * @tparam E 不期待值的类型 */ template class DExpected { static_assert(__dexpected::_can_be_dunexpected(), "type E can't be DUnexpected."); static constexpr bool des_value() { return !std::is_trivially_destructible::value; } template friend class DExpected; template > static constexpr bool __cons_from_DExpected() { return std::is_constructible &>::value and std::is_constructible>::value and std::is_constructible &>::value and std::is_constructible>::value; } template void assign_err(V &&_v) { if (m_has_value) { construct_at(std::addressof(m_error), std::forward(_v)); m_has_value = false; } else { m_error = std::forward(_v); } } public: using value_type = void; using error_type = E; using dunexpected_type = DUnexpected; template using rebind = DExpected; constexpr DExpected() noexcept : m_has_value(true) , m_void() { } template ::value, bool>::type = true> DExpected(const DExpected &_x) noexcept(std::is_nothrow_copy_constructible::value) : m_has_value(_x.m_has_value) , m_void() { if (!m_has_value) construct_at(std::addressof(m_error), _x.m_error); } template ::value, bool>::type = true> DExpected(DExpected &&_x) noexcept(std::is_nothrow_move_constructible::value) : m_has_value(_x.m_has_value) , m_void() { if (!m_has_value) construct_at(std::addressof(m_error), std::move(_x).m_error); } template ::value and std::is_constructible::value and !__cons_from_DExpected() and !std::is_convertible::value, bool>::type = true> explicit DExpected(const DExpected &_x) noexcept(std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) , m_void() { if (!m_has_value) construct_at(std::addressof(m_error), _x.m_error); } template ::value and std::is_constructible::value and !__cons_from_DExpected() and std::is_convertible::value, bool>::type = true> DExpected(const DExpected &_x) noexcept(std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) , m_void() { if (!m_has_value) construct_at(std::addressof(m_error), _x.m_error); } template ::value and std::is_constructible::value and __cons_from_DExpected() and !std::is_convertible::value, bool>::type = true> explicit DExpected(DExpected &&_x) noexcept(std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) , m_void() { if (!m_has_value) construct_at(std::addressof(m_error), std::move(_x).m_error); } template ::value and std::is_constructible::value and __cons_from_DExpected() and std::is_convertible::value, bool>::type = true> DExpected(DExpected &&_x) noexcept(std::is_nothrow_constructible::value) : m_has_value(_x.m_has_value) , m_void() { if (!m_has_value) construct_at(std::addressof(m_error), std::move(_x).m_error); } template ::value and !std::is_convertible::value, bool>::type = true> constexpr explicit DExpected(const DUnexpected &_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(_u.error()) { } template ::value and std::is_convertible::value, bool>::type = true> constexpr DExpected(const DUnexpected &_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(_u.error()) { } template < typename G = E, typename std::enable_if::value and !std::is_convertible::value, bool>::type = true> constexpr explicit DExpected(DUnexpected &&_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(std::move(_u).error()) { } template ::value and std::is_convertible::value, bool>::type = true> constexpr DExpected(DUnexpected &&_u) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(std::move(_u).error()) { } template constexpr explicit DExpected(emplace_tag) noexcept : DExpected() { } template constexpr explicit DExpected(dunexpected_tag, Args &&...args) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(std::forward(args)...) { static_assert(std::is_constructible::value, "type E can't construct from args"); } template constexpr explicit DExpected(dunexpected_tag, std::initializer_list _li, Args &&...args) noexcept(std::is_nothrow_constructible::value) : m_has_value(false) , m_error(_li, std::forward(args)...) { static_assert(std::is_constructible &, Args...>::value, "type E can't construct from args"); } ~DExpected() { if (des_value() and !m_has_value) { destroy_at(std::addressof(m_error)); } } DExpected &operator=(const DExpected &) = delete; template < typename std::enable_if::value and std::is_copy_assignable::value, bool>::type = true> DExpected &operator=(const DExpected &_x) noexcept( std::is_nothrow_copy_constructible::value and std::is_nothrow_copy_assignable::value) { if (_x.m_has_value) emplace(); else assign_err(_x.m_error); return *this; } template < typename std::enable_if::value and std::is_move_assignable::value, bool>::type = true> DExpected & operator=(DExpected &&_x) noexcept(std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value) { if (_x.m_has_value) emplace(); else assign_err(std::move(_x.m_error)); return *this; } template ::value and std::is_assignable::value, bool>::type = true> DExpected &operator=(const DUnexpected &_e) { assign_err(_e.error()); return *this; } template < typename G, typename std::enable_if::value and std::is_assignable::value, bool>::type = true> DExpected &operator=(DUnexpected &&_e) { assign_err(std::move(_e.error())); return *this; } void emplace() noexcept { if (!m_has_value) { destroy_at(std::addressof(m_error)); m_has_value = true; } } template ::value, bool>::type = true> void swap(DExpected &_x) noexcept(std::is_nothrow_move_constructible::value) { if (m_has_value) { if (!_x.m_has_value) { construct_at(std::addressof(m_error), std::move(_x.m_error)); destroy_at(std::addressof(_x.m_error)); m_has_value = false; _x.m_has_value = true; } } else { if (_x.m_has_value) { construct_at(std::addressof(_x.m_error), std::move(m_error)); destroy_at(std::addressof(m_error)); m_has_value = true; _x.m_has_value = false; } else { using std::swap; swap(m_error, _x.m_error); } } } constexpr explicit operator bool() const noexcept { return m_has_value; } constexpr bool hasValue() const noexcept { return m_has_value; } void operator*() const noexcept { assert(m_has_value); } void value() const & { if (likely(m_has_value)) return; _DEXPECTED_THROW_OR_ABORT(bad_result_access(m_error)); } void value() && { if (likely(m_has_value)) return; _DEXPECTED_THROW_OR_ABORT(bad_result_access(std::move(m_error))); } const E &error() const &noexcept { assert(!m_has_value); return m_error; } E &error() &noexcept { assert(!m_has_value); return m_error; } const E &&error() const &&noexcept { assert(!m_has_value); return std::move(m_error); } E &&error() &&noexcept { assert(!m_has_value); return std::move(m_error); } template ::value, bool>::type = true> friend bool operator==(const DExpected &_x, const DExpected &_y) noexcept(noexcept(bool(_x.error() == _y.error()))) { if (_x.hasValue()) return _y.hasValue(); else return !_y.hasValue() and bool(_x.error() == _y.error()); } template friend bool operator==(const DExpected &_x, const DUnexpected &_e) noexcept(noexcept(bool(_x.error() == _e.error()))) { return !_x.hasValue() && bool(_x.error() == _e.error()); } // TODO:可能没有swap friend void swap(DExpected &_x, DExpected &_y) noexcept(noexcept(_x.swap(_y))) { _x.swap(_y); } private: bool m_has_value; union { struct { } m_void; E m_error; }; }; DCORE_END_NAMESPACE #endif dtkcore-5.7.12/include/base/dobject.h000066400000000000000000000016411476226660600174020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DOBJECT_H #define DOBJECT_H #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE #define D_DECLARE_PRIVATE(Class) Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_d_ptr),Class) #define D_DECLARE_PUBLIC(Class) Q_DECLARE_PUBLIC(Class) #define D_D(Class) Q_D(Class) #define D_Q(Class) Q_Q(Class) #define D_DC(Class) Q_D(const Class) #define D_QC(Class) Q_Q(const Class) #define D_PRIVATE_SLOT(Func) Q_PRIVATE_SLOT(d_func(), Func) class DObjectPrivate; class LIBDTKCORESHARED_EXPORT DObject { protected: DObject(DObject *parent = nullptr); DObject(DObjectPrivate &dd, DObject *parent = nullptr); virtual ~DObject(); QScopedPointer d_d_ptr; Q_DISABLE_COPY(DObject) D_DECLARE_PRIVATE(DObject) }; DCORE_END_NAMESPACE #endif // DOBJECT_H dtkcore-5.7.12/include/base/dsingleton.h000066400000000000000000000027161476226660600201420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DSINGLETON_H #define DSINGLETON_H #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE /*! a simple singleton template for std c++ 11 or later. example: \code class ExampleSingleton : public QObject, public Dtk::DSingleton { Q_OBJECT friend class DSingleton; }; \endcode \note: for Qt, "public DSingleton" must be after QObject. */ /*! 通过c++11的特性实现的单例模板 使用示例: ``` class ExampleSingleton : public QObject, public Dtk::DSingleton { Q_OBJECT friend class DSingleton; }; ``` \note 对于Qt程序 public DSingleton" 必须在卸载QObject后面出现。 */ template class LIBDTKCORESHARED_EXPORT DSingleton { public: #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QT_DEPRECATED_X("Use ref") static inline T *instance() { static T *_instance = new T; return _instance; } #endif static T& ref() { static T instance; return instance; } DSingleton(T&&) = delete; DSingleton(const T&) = delete; void operator= (const T&) = delete; protected: DSingleton() = default; virtual ~DSingleton() = default; }; DCORE_END_NAMESPACE #endif // DSINGLETON_H dtkcore-5.7.12/include/base/private/000077500000000000000000000000001476226660600172675ustar00rootroot00000000000000dtkcore-5.7.12/include/base/private/dobject_p.h000066400000000000000000000007241476226660600213740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DOBJECT_P_H #define DOBJECT_P_H #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DObject; class LIBDTKCORESHARED_EXPORT DObjectPrivate { public: virtual ~DObjectPrivate(); protected: DObjectPrivate(DObject *qq); DObject *q_ptr; Q_DECLARE_PUBLIC(DObject) }; DCORE_END_NAMESPACE #endif // DOBJECT_P_H dtkcore-5.7.12/include/dci/000077500000000000000000000000001476226660600154425ustar00rootroot00000000000000dtkcore-5.7.12/include/dci/ddcifile.h000066400000000000000000000036751476226660600173710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #ifndef DTK_NO_PROJECT #include #include #else #define DCORE_BEGIN_NAMESPACE #define DCORE_END_NAMESPACE #define LIBDTKCORESHARED_EXPORT #define D_DECLARE_PRIVATE(Class) Class##Private *d; #endif #include QT_BEGIN_NAMESPACE class QIODevice; QT_END_NAMESPACE DCORE_BEGIN_NAMESPACE class DDciFilePrivate; class LIBDTKCORESHARED_EXPORT DDciFile #ifndef DTK_NO_PROJECT : public DObject #endif { D_DECLARE_PRIVATE(DDciFile) public: enum FileType { UnknowFile, File = 1, Directory = 2, Symlink = 3 }; static void registerFileEngine(); DDciFile(); explicit DDciFile(const QString &fileName); explicit DDciFile(const QByteArray &data); bool isValid() const; QString lastErrorString() const; bool writeToFile(const QString &fileName) const; bool writeToDevice(QIODevice *device) const; QByteArray toData() const; static constexpr int metadataSizeV1(); // for reader QStringList list(const QString &dir, bool onlyFileName = false) const; int childrenCount(const QString &dir) const; bool exists(const QString &filePath) const; FileType type(const QString &filePath) const; QByteArray dataRef(const QString &filePath) const; QString name(const QString &filePath) const; QString symlinkTarget(const QString &filePath, bool originData = false) const; // for writer bool mkdir(const QString &filePath); bool writeFile(const QString &filePath, const QByteArray &data, bool override = false); bool remove(const QString &filePath); bool rename(const QString &filePath, const QString &newFilePath, bool override = false); bool copy(const QString &from, const QString &to); bool link(const QString &source, const QString &to); }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/filesystem/000077500000000000000000000000001476226660600170675ustar00rootroot00000000000000dtkcore-5.7.12/include/filesystem/dbasefilewatcher.h000066400000000000000000000027371476226660600225450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DBASEFILEWATCHER_H #define DBASEFILEWATCHER_H #include "dtkcore_global.h" #include "dobject.h" #include DCORE_BEGIN_NAMESPACE class DBaseFileWatcherPrivate; class LIBDTKCORESHARED_EXPORT DBaseFileWatcher : public QObject, public DObject { Q_OBJECT public: ~DBaseFileWatcher(); QUrl fileUrl() const; bool startWatcher(); bool stopWatcher(); bool restartWatcher(); virtual void setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled = true); using SignalType1 = void(DBaseFileWatcher::*)(const QUrl &); using SignalType2 = void(DBaseFileWatcher::*)(const QUrl &, const QUrl &); static bool ghostSignal(const QUrl &targetUrl, SignalType1 signal, const QUrl &arg1); static bool ghostSignal(const QUrl &targetUrl, SignalType2 signal, const QUrl &arg1, const QUrl &arg2); Q_SIGNALS: void fileDeleted(const QUrl &url); void fileAttributeChanged(const QUrl &url); void fileMoved(const QUrl &fromUrl, const QUrl &toUrl); void subfileCreated(const QUrl &url); void fileModified(const QUrl &url); void fileClosed(const QUrl &url); protected: explicit DBaseFileWatcher(DBaseFileWatcherPrivate &dd, const QUrl &url, QObject *parent = 0); private: Q_DISABLE_COPY(DBaseFileWatcher) D_DECLARE_PRIVATE(DBaseFileWatcher) }; DCORE_END_NAMESPACE #endif // DBASEFILEWATCHER_H dtkcore-5.7.12/include/filesystem/dcapfile.h000066400000000000000000000061441476226660600210140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DCAPFILE_H #define DCAPFILE_H #include #include #include #include DCORE_BEGIN_NAMESPACE class DCapFilePrivate; class DCapFile : public QFile, public DObject { Q_OBJECT D_DECLARE_PRIVATE(DCapFile) Q_DISABLE_COPY(DCapFile) public: explicit DCapFile(QObject *parent = nullptr); DCapFile(const QString &name, QObject *parent = nullptr); ~DCapFile() override; void setFileName(const QString &name); bool exists() const; static bool exists(const QString &fileName); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED_X("Use QFile::symLinkTarget() instead") QString readLink() const; #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QString symLinkTarget() const; #endif bool remove(); static bool remove(const QString &fileName); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) bool moveToTrash(); static bool moveToTrash(const QString &fileName, QString *pathInTrash = nullptr); #endif bool rename(const QString &newName); static bool rename(const QString &oldName, const QString &newName); bool link(const QString &newName); static bool link(const QString &oldname, const QString &newName); bool copy(const QString &newName); static bool copy(const QString &fileName, const QString &newName); bool open(OpenMode flags) override; bool resize(qint64 sz) override; static bool resize(const QString &filename, qint64 sz); private: bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle); bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle); }; class DCapDirPrivate; class DCapDir : public QDir { public: DCapDir(const DCapDir &); DCapDir(const QString &path = QString()); DCapDir(const QString &path, const QString &nameFilter, SortFlags sort = SortFlags(Name | IgnoreCase), Filters filter = AllEntries); ~DCapDir(); void setPath(const QString &path); bool cd(const QString &dirName); QStringList entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const; QStringList entryList(const QStringList &nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) const; QFileInfoList entryInfoList(Filters filters = NoFilter, SortFlags sort = NoSort) const; QFileInfoList entryInfoList(const QStringList &nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) const; bool mkdir(const QString &dirName) const; bool rmdir(const QString &dirName) const; bool mkpath(const QString &dirPath) const; bool rmpath(const QString &dirPath) const; bool exists() const; bool remove(const QString &fileName); bool rename(const QString &oldName, const QString &newName); bool exists(const QString &name) const; private: QSharedDataPointer dd_ptr; }; DCORE_END_NAMESPACE Q_DECLARE_SHARED(DTK_CORE_NAMESPACE::DCapDir) #endif // DCAPFILE_H dtkcore-5.7.12/include/filesystem/dcapmanager.h000066400000000000000000000020331476226660600215000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DCAPMANAGER_H #define DCAPMANAGER_H #include #include DCORE_BEGIN_NAMESPACE class DCapManagerPrivate; class DCapManager : public QObject, public DObject { Q_OBJECT Q_DISABLE_COPY(DCapManager) D_DECLARE_PRIVATE(DCapManager) public: static DCapManager *instance(); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QT_DEPRECATED_X("This api will no longer take effect, please use DCapDir or DCapFile") static void registerFileEngine(); QT_DEPRECATED_X("This api will no longer take effect, please use DCapDir or DCapFile") static void unregisterFileEngine(); #endif void appendPath(const QString &path); void appendPaths(const QStringList &pathList); void removePath(const QString &path); void removePaths(const QStringList &paths); QStringList paths() const; protected: explicit DCapManager(); }; DCORE_END_NAMESPACE #endif // DCAPMANAGER_H dtkcore-5.7.12/include/filesystem/dfilesystemwatcher.h000066400000000000000000000030451476226660600231500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILESYSTEMWATCHER_H #define DFILESYSTEMWATCHER_H #include "dtkcore_global.h" #include "dobject.h" #include DCORE_BEGIN_NAMESPACE class DFileSystemWatcherPrivate; class LIBDTKCORESHARED_EXPORT DFileSystemWatcher : public QObject, public DObject { Q_OBJECT D_DECLARE_PRIVATE(DFileSystemWatcher) public: DFileSystemWatcher(QObject *parent = Q_NULLPTR); DFileSystemWatcher(const QStringList &paths, QObject *parent = Q_NULLPTR); ~DFileSystemWatcher(); bool addPath(const QString &file); QStringList addPaths(const QStringList &files); bool removePath(const QString &file); QStringList removePaths(const QStringList &files); QStringList files() const; QStringList directories() const; Q_SIGNALS: void fileDeleted(const QString &path, const QString &name, QPrivateSignal); void fileAttributeChanged(const QString &path, const QString &name, QPrivateSignal); void fileClosed(const QString &path, const QString &name, QPrivateSignal); void fileMoved(const QString &fromPath, const QString &fromName, const QString &toPath, const QString &toName, QPrivateSignal); void fileCreated(const QString &path, const QString &name, QPrivateSignal); void fileModified(const QString &path, const QString &name, QPrivateSignal); private: Q_PRIVATE_SLOT(d_func(), void _q_readFromInotify()) }; DCORE_END_NAMESPACE #endif // DFILESYSTEMWATCHER_H dtkcore-5.7.12/include/filesystem/dfilewatcher.h000066400000000000000000000017671476226660600217140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEWATCHER_H #define DFILEWATCHER_H #include "dbasefilewatcher.h" DCORE_BEGIN_NAMESPACE class DFileWatcherPrivate; class LIBDTKCORESHARED_EXPORT DFileWatcher : public DBaseFileWatcher { Q_OBJECT public: explicit DFileWatcher(const QString &filePath, QObject *parent = 0); private Q_SLOTS: void onFileDeleted(const QString &path, const QString &name); void onFileAttributeChanged(const QString &path, const QString &name); void onFileMoved(const QString &fromPath, const QString &fromName, const QString &toPath, const QString &toName); void onFileCreated(const QString &path, const QString &name); void onFileModified(const QString &path, const QString &name); void onFileClosed(const QString &path, const QString &name); private: D_DECLARE_PRIVATE(DFileWatcher) }; DCORE_END_NAMESPACE #endif // DFILEWATCHER_H dtkcore-5.7.12/include/filesystem/dfilewatchermanager.h000066400000000000000000000023251476226660600232360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEWATCHERMANAGER_H #define DFILEWATCHERMANAGER_H #include "dtkcore_global.h" #include "dobject.h" #include #include DCORE_BEGIN_NAMESPACE class DFileWatcher; class DFileWatcherManagerPrivate; class LIBDTKCORESHARED_EXPORT DFileWatcherManager : public QObject, public DObject { Q_OBJECT public: explicit DFileWatcherManager(QObject *parent = 0); ~DFileWatcherManager(); DFileWatcher *add(const QString &filePath); void remove(const QString &filePath); void removeAll(); QStringList watchedFiles() const; Q_SIGNALS: void fileDeleted(const QString &filePath); void fileAttributeChanged(const QString &filePath); void fileMoved(const QString &fromFilePath, const QString &toFilePath); void subfileCreated(const QString &filePath); void fileModified(const QString &filePath); void fileClosed(const QString &filePath); private: QScopedPointer d_ptr; D_DECLARE_PRIVATE(DFileWatcherManager) Q_DISABLE_COPY(DFileWatcherManager) }; DCORE_END_NAMESPACE #endif // DFILEWATCHERMANAGER_H dtkcore-5.7.12/include/filesystem/dpathbuf.h000066400000000000000000000017161476226660600210420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DPathBuf { public: DPathBuf(); DPathBuf(const QString &path); DPathBuf operator/(const QString &p) const { return DPathBuf(m_path + "/" + p); } DPathBuf &operator/=(const QString &p) { return join(p); } DPathBuf operator/(const char *p) const { return operator /(QString(p)); } DPathBuf &operator/=(const char *p) { return operator /=(QString(p)); } DPathBuf &join(const QString &p) { m_path += "/" + p; m_path = QDir(m_path).absolutePath(); return *this; } QString toString() const { return QDir::toNativeSeparators(m_path); } private: QString m_path; }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/filesystem/dstandardpaths.h000066400000000000000000000055121476226660600222470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTK_CORE_FILESYSTEM_DSTANDARDPATHS_H #define DTK_CORE_FILESYSTEM_DSTANDARDPATHS_H #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DStandardPathsPrivate; class LIBDTKCORESHARED_EXPORT DStandardPaths { public: enum Mode { Auto, Snap, Test, }; static QString writableLocation(QStandardPaths::StandardLocation type); static QStringList standardLocations(QStandardPaths::StandardLocation type); static QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile); static QStringList locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile); static QString findExecutable(const QString &executableName, const QStringList &paths = QStringList()); static void setMode(Mode mode); /** * @brief About XDG dir, view it in https://gitlab.freedesktop.org/xdg/xdg-specs/ */ enum class XDG { /* * @brief DataHome, usually is ~/.local/share, also can be defined by ${XDG_DATA_HOME}, where stores the data of applications */ DataHome, /* * @brief ConfigHome, usually is ~/.config, can be defined by ${XDG_CONFIG_HOME}, where stores the config of applications */ ConfigHome, /* * @brief CacheHome, usually is ~/.cache, can be defined by ${XDG_CACHE_HOME}, where stores caches, can be always cleared */ CacheHome, /* * @brief Where temp files or sock files always be put in, like sddm.sock. It is unique per session. It is /run/user/${uid} or ${XDG_RUNTIME_DIR}, */ RuntimeDir, #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) RuntimeTime [[deprecated("Use RuntimeDir Instead")]] = RuntimeDir, #endif /* * @brief where history file and state file should be. It is induced because users do not want to mix their config files and state files. It is always ~/.local/state, or defined by ${XDG_STATE_HOME} */ StateHome }; enum class DSG { AppData, DataDir }; static QString homePath(); static QString homePath(const uint uid); /* * @brief Get the XDG dir path by XDG type */ static QString path(XDG type); static QString path(DSG type); static QStringList paths(DSG type); static QString filePath(XDG type, QString fileName); static QString filePath(DSG type, QString fileName); private: DStandardPaths(); ~DStandardPaths(); Q_DISABLE_COPY(DStandardPaths) }; DCORE_END_NAMESPACE #endif // DTK_CORE_FILESYSTEM_DSTANDARDPATHS_H dtkcore-5.7.12/include/filesystem/dtrashmanager.h000066400000000000000000000012531476226660600220610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTRASHMANAGER_H #define DTRASHMANAGER_H #include #include #include DCORE_BEGIN_NAMESPACE class DTrashManagerPrivate; class LIBDTKCORESHARED_EXPORT DTrashManager : public QObject, public DObject { public: static DTrashManager *instance(); bool trashIsEmpty() const; bool cleanTrash(); bool moveToTrash(const QString &filePath, bool followSymlink = false); protected: DTrashManager(); private: D_DECLARE_PRIVATE(DTrashManager) }; DCORE_END_NAMESPACE #endif // DTRASHMANAGER_H dtkcore-5.7.12/include/global/000077500000000000000000000000001476226660600161435ustar00rootroot00000000000000dtkcore-5.7.12/include/global/dconfig.h000066400000000000000000000053341476226660600177320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DCONFIG_H #define DCONFIG_H #include #include #include #include DCORE_BEGIN_NAMESPACE class DConfigBackend { public: virtual ~DConfigBackend(); virtual bool isValid() const = 0; virtual bool load(const QString &/*appId*/) = 0; virtual QStringList keyList() const = 0; virtual QVariant value(const QString &/*key*/, const QVariant &/*fallback*/) const = 0; virtual void setValue(const QString &/*key*/, const QVariant &/*value*/) = 0; virtual void reset(const QString &key) { setValue(key, QVariant());} virtual QString name() const {return QString("");} virtual bool isDefaultValue(const QString &/*key*/) const { return true; } }; class DConfigPrivate; class LIBDTKCORESHARED_EXPORT DConfig : public QObject, public DObject { Q_OBJECT D_DECLARE_PRIVATE(DConfig) Q_PROPERTY(QStringList keyList READ keyList CONSTANT FINAL) public: explicit DConfig(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); explicit DConfig(DConfigBackend *backend, const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); static DConfig *create(const QString &appId, const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); static DConfig *create(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); static DConfig *createGeneric(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); static DConfig *createGeneric(DConfigBackend *backend, const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); static void setAppId(const QString &appId); static QThread *globalThread(); QString backendName() const; QStringList keyList() const; bool isValid() const; bool isDefaultValue(const QString &key) const; QVariant value(const QString &key, const QVariant &fallback = QVariant()) const; void setValue(const QString &key, const QVariant &value); void reset(const QString &key); QString name() const; QString subpath() const; Q_SIGNALS: void valueChanged(const QString &key); private: explicit DConfig(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr); }; DCORE_END_NAMESPACE #endif // DCONFIG_H dtkcore-5.7.12/include/global/dconfigfile.h000066400000000000000000000102551476226660600205700ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DCONFIGFILE_H #define DCONFIGFILE_H #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QIODevice; QT_END_NAMESPACE DCORE_BEGIN_NAMESPACE class DConfigMeta; class DConfigCache; class DConfigFilePrivate; class LIBDTKCORESHARED_EXPORT DConfigFile : public DObject{ D_DECLARE_PRIVATE(DConfigFile) public: enum Flag { NoOverride = 1 << 0, Global = 1 << 1, UserPublic = 1 << 2 }; Q_DECLARE_FLAGS(Flags, Flag) enum Permissions { ReadOnly, ReadWrite }; enum Visibility { Private, Public }; struct Version { quint16 major; quint16 minor; }; static constexpr Version supportedVersion(); explicit DConfigFile(const QString &appId, const QString &name, const QString &subpath = QString()); explicit DConfigFile(const DConfigFile &other); bool load(const QString &localPrefix = QString()); bool load(QIODevice *meta, const QList &overrides); bool save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) const; bool isValid() const; QVariant value(const QString &key, DConfigCache *userCache = nullptr) const; QVariant cacheValue(DConfigCache *userCache, const QString &key) const; bool setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache = nullptr); DConfigCache *createUserCache(const uint uid); DConfigCache *globalCache() const; DConfigMeta *meta(); protected: friend QDebug operator<<(QDebug, const DConfigFile &); }; class LIBDTKCORESHARED_EXPORT DConfigMeta { public: virtual ~DConfigMeta(); virtual DConfigFile::Version version() const = 0; virtual void setVersion(quint16 major, quint16 minor) = 0; virtual bool load(const QString &localPrefix = QString()) = 0; virtual bool load(QIODevice *meta, const QList &overrides) = 0; virtual QStringList keyList() const = 0; virtual DConfigFile::Flags flags(const QString &key) const = 0; virtual DConfigFile::Permissions permissions(const QString &key) const = 0; virtual DConfigFile::Visibility visibility(const QString &key) const = 0; virtual int serial(const QString &key) const = 0; virtual QString displayName(const QString &key, const QLocale &locale) = 0; virtual QString description(const QString &key, const QLocale &locale) = 0; virtual QString metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0; virtual QStringList allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0; virtual QVariant value(const QString &key) const = 0; static QStringList genericMetaDirs(const QString &localPrefix = QString()); static QStringList applicationMetaDirs(const QString &localPrefix, const QString &appId); }; class LIBDTKCORESHARED_EXPORT DConfigCache { public: virtual ~DConfigCache(); virtual bool load(const QString &localPrefix = QString()) = 0; virtual bool save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0; virtual bool isGlobal() const = 0; virtual void remove(const QString &key) = 0; virtual QStringList keyList() const = 0; virtual bool setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &callerAppid) = 0; virtual QVariant value(const QString &key) const = 0; virtual int serial(const QString &key) const = 0; virtual uint uid() const = 0; virtual void setCachePathPrefix(const QString &prefix) = 0; }; #ifndef QT_NO_DEBUG_STREAM Q_CORE_EXPORT QDebug operator<<(QDebug, const DConfigFile &); #endif Q_DECLARE_OPERATORS_FOR_FLAGS(DConfigFile::Flags) DCORE_END_NAMESPACE #endif // DCONFIGFILE_H dtkcore-5.7.12/include/global/ddesktopentry.h000066400000000000000000000070341476226660600212170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include "dtkcore_global.h" #include #include #include DCORE_BEGIN_NAMESPACE class DDesktopEntryPrivate; class LIBDTKCORESHARED_EXPORT DDesktopEntry { Q_GADGET public: enum EntryType { Unknown = 0, //!<@~english Unknown desktop file type. Maybe is invalid. Application, //!<@~english The file describes application. Link, //!<@~english The file describes URL. Directory, //!<@~english The file describes directory settings. ServiceType, //!<@~english KDE specific type. mentioned in the spec, so listed here too. Service, //!<@~english KDE specific type. mentioned in the spec, so listed here too. FSDevice //!<@~english KDE specific type. mentioned in the spec, so listed here too. }; Q_ENUM(EntryType) enum ValueType { Unparsed = 0, // Maybe useless, consider remove it? String, Strings, Boolean, Numeric, NotExisted = 99 }; Q_ENUM(ValueType) enum Status { NoError = 0, //!<@~english No error occurred. AccessError, //!<@~english An access error occurred (e.g. trying to write to a read-only file). FormatError //!<@~english A format error occurred (e.g. loading a malformed desktop entry file). }; Q_ENUM(Status) explicit DDesktopEntry(const QString &filePath) noexcept; ~DDesktopEntry(); bool save() const; Status status() const; QStringList keys(const QString §ion = "Desktop Entry") const; QStringList allGroups(bool sorted = false) const; bool contains(const QString &key, const QString §ion = "Desktop Entry") const; QString name() const; QString genericName() const; QString ddeDisplayName() const; QString comment() const; QString rawValue(const QString &key, const QString §ion = "Desktop Entry", const QString &defaultValue = QString()) const; QString stringValue(const QString &key, const QString §ion = "Desktop Entry", const QString &defaultValue = QString()) const; QString localizedValue(const QString &key, const QString &localeKey = "default", const QString §ion = "Desktop Entry", const QString& defaultValue = QString()) const; QString localizedValue(const QString &key, const QLocale &locale, const QString §ion = "Desktop Entry", const QString& defaultValue = QString()) const; QStringList stringListValue(const QString &key, const QString §ion = "Desktop Entry") const; bool setRawValue(const QString &value, const QString &key, const QString& section = "Desktop Entry"); bool setStringValue(const QString &value, const QString &key, const QString& section = "Desktop Entry"); bool setLocalizedValue(const QString &value, const QString& localeKey, const QString &key, const QString& section = "Desktop Entry"); bool removeEntry(const QString &key, const QString §ion = "Desktop Entry"); static QString &escape(QString &str); static QString &escapeExec(QString &str); static QString &unescape(QString &str, bool unescapeSemicolons = false); static QString &unescapeExec(QString &str); protected: bool setStatus(const Status &status); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(DDesktopEntry) }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/global/dlicenseinfo.h000066400000000000000000000023571476226660600207650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DLICENSEINFO_H #define DLICENSEINFO_H #include #include #include DCORE_BEGIN_NAMESPACE class DLicenseInfoPrivate; class LIBDTKCORESHARED_EXPORT DLicenseInfo : public DObject { public: explicit DLicenseInfo(DObject *parent = nullptr); bool loadContent(const QByteArray &content); bool loadFile(const QString &file); void setLicenseSearchPath(const QString &path); QByteArray licenseContent(const QString &licenseName); class DComponentInfoPrivate; class LIBDTKCORESHARED_EXPORT DComponentInfo : public DObject { public: explicit DComponentInfo(DObject *parent = nullptr); ~DComponentInfo() override; QString name() const; QString version() const; QString copyRight() const; QString licenseName() const; private: D_DECLARE_PRIVATE(DComponentInfo) friend class DLicenseInfoPrivate; }; using DComponentInfos = QVector; DComponentInfos componentInfos() const; private: D_DECLARE_PRIVATE(DLicenseInfo) }; DCORE_END_NAMESPACE #endif // DLICENSEINFO_H dtkcore-5.7.12/include/global/dsecurestring.h000066400000000000000000000006311476226660600211750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include "dtkcore_global.h" #include DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DSecureString : public QString { public: using QString::QString; DSecureString(const QString &other) noexcept; ~DSecureString(); }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/global/dsgapplication.h000066400000000000000000000006211476226660600213140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DSGAPPLICATION_H #define DSGAPPLICATION_H #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DSGApplication { public: static QByteArray id(); static QByteArray getId(qint64 pid); }; DCORE_END_NAMESPACE #endif // DSGAPPLICATION_H dtkcore-5.7.12/include/global/dsysinfo.h000066400000000000000000000135451476226660600201620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DSYSINFO_H #define DSYSINFO_H #include #include DCORE_BEGIN_NAMESPACE class DSysInfoPrivate; class LIBDTKCORESHARED_EXPORT DSysInfo { Q_GADGET public: enum ProductType { UnknownType = 0, Deepin, ArchLinux, CentOS, Debian, Fedora, LinuxMint, Manjaro, openSUSE, SailfishOS, Ubuntu, Uos, Gentoo, NixOS }; Q_ENUM(ProductType) enum DeepinType { UnknownDeepin = 0, DeepinDesktop, DeepinProfessional, DeepinServer, DeepinPersonal, DeepinMilitary }; enum LogoType { Normal = 0, Light, Symbolic, Transparent }; enum OrgType { Distribution, //!<@~english distribution itself Distributor, //!<@~english distributer of the current distribution Manufacturer //!<@~english manufacturer of the current distribution or device }; enum UosType { UosTypeUnknown, UosDesktop, UosServer, UosDevice, UosSmart, UosTypeCount // must at last }; enum UosEdition { UosEditionUnknown, UosProfessional, UosHome, UosCommunity, UosMilitary, UosEnterprise, UosEnterpriseC, UosEuler, UosMilitaryS, // for Server UosDeviceEdition, UosEducation, UosEditionCount // must at last }; enum UosArch { UosArchUnknown, UosAMD64 = 1 << 0, UosARM64 = 1 << 1, UosMIPS64 = 1 << 2, UosSW64 = 1 << 3 }; //! @~english enum.Arch enum Arch { ARM64, /*!< @~english arm64 */ ARM64_BE, /*!< @~english arm64-be */ ARM, /*!< @~english arm */ ARM_BE, /*!< @~english arm-be */ ALPHA, /*!< @~english alpha */ SW_64, /*!< @~english sw_64 */ ARC, /*!< @~english arc */ ARC_BE, /*!< @~english arc-be */ CRIS, /*!< @~english cris */ X86_64, /*!< @~english x86-64 */ X86, /*!< @~english x86 */ IA64, /*!< @~english ia64 */ LOONGARCH64,/*!< @~english loongarch64 */ M68K, /*!< @~english m68k */ MIPS64_LE, /*!< @~english mips64-le */ MIPS64, /*!< @~english mips64 */ MIPS_LE, /*!< @~english mips-le */ MIPS, /*!< @~english mips */ NIOS2, /*!< @~english nios2 */ PARISC64, /*!< @~english parisc64 */ PARISC, /*!< @~english parisc */ PPC64_LE, /*!< @~english ppc64-le */ PPC64, /*!< @~english ppc64 */ PPC, /*!< @~english ppc */ PPC_LE, /*!< @~english ppc-le */ RISCV32, /*!< @~english riscv32 */ RISCV64, /*!< @~english riscv64 */ S390X, /*!< @~english s390x */ S390, /*!< @~english s390 */ SH64, /*!< @~english sh64 */ SH, /*!< @~english sh */ SPARC64, /*!< @~english sparc64 */ SPARC, /*!< @~english sparc */ TILEGX, /*!< @~english tilegx */ NUM_ARCHES, /*!< @~english number of defined Arch types */ }; Q_ENUM(Arch) // Q_GADGET #ifdef Q_OS_LINUX static bool isDeepin(); static bool isDDE(); static DeepinType deepinType(); static QString deepinTypeDisplayName(const QLocale &locale = QLocale::system()); static QString deepinVersion(); static QString deepinEdition(); static QString deepinCopyright(); // uos version interface static UosType uosType(); static UosEdition uosEditionType(); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) Q_DECL_DEPRECATED_X("Use arch() instead") static UosArch uosArch(); #endif static QString uosProductTypeName(const QLocale &locale = QLocale::system()); static QString uosSystemName(const QLocale &locale = QLocale::system()); static QString uosEditionName(const QLocale &locale = QLocale::system()); static QString spVersion(); // SP1...SP99 static QString udpateVersion(); // update1...update9 static QString majorVersion(); static QString minorVersion(); static QString buildVersion(); // xyzs #endif #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) Q_DECL_DEPRECATED_X("Use distributionInfoPath() instead") static QString deepinDistributionInfoPath(); Q_DECL_DEPRECATED_X("Use distributionOrgName() instead") static QString deepinDistributorName(); Q_DECL_DEPRECATED_X("Use distributionOrgWebsite() instead") static QPair deepinDistributorWebsite(); Q_DECL_DEPRECATED_X("Use distributionOrgLogo() instead") static QString deepinDistributorLogo(LogoType type = Normal, const QString & fallback = QString()); #endif static QString distributionInfoPath(); static QString distributionInfoSectionName(OrgType type); static QString distributionOrgName(OrgType type = Distribution, const QLocale &locale = QLocale::system()); static QPair distributionOrgWebsite(OrgType type = Distribution); static QString distributionOrgLogo(OrgType orgType = Distribution, LogoType type = Normal, const QString & fallback = QString()); static QString operatingSystemName(); static ProductType productType(); static QString productTypeString(); static QString productVersion(); static bool isCommunityEdition(); static QString computerName(); static QString cpuModelName(); static qint64 memoryInstalledSize(); static qint64 memoryTotalSize(); static qint64 systemDiskSize(); static QDateTime bootTime(); static QDateTime shutdownTime(); static qint64 uptime(); static Arch arch(); }; DCORE_END_NAMESPACE #endif // DSYSINFO_H dtkcore-5.7.12/include/global/dtkcore_global.h000066400000000000000000000037451476226660600213000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #define DTK_NAMESPACE Dtk #if !defined(DTK_NAMESPACE) # define DTK_BEGIN_NAMESPACE # define DTK_END_NAMESPACE # define DTK_USE_NAMESPACE #else # define DTK_BEGIN_NAMESPACE namespace DTK_NAMESPACE { # define DTK_END_NAMESPACE } # define DTK_USE_NAMESPACE using namespace DTK_NAMESPACE; #endif #define DCORE_NAMESPACE Core #define DTK_CORE_NAMESPACE DTK_NAMESPACE::DCORE_NAMESPACE #if !defined(DCORE_NAMESPACE) # define DCORE_BEGIN_NAMESPACE # define DCORE_END_NAMESPACE # define DCORE_USE_NAMESPACE #else # define DCORE_BEGIN_NAMESPACE namespace DTK_NAMESPACE { namespace DCORE_NAMESPACE { # define DCORE_END_NAMESPACE }} # define DCORE_USE_NAMESPACE using namespace DTK_CORE_NAMESPACE; #endif #if defined(DTK_STATIC_LIB) # define LIBDTKCORESHARED_EXPORT #else #if defined(LIBDTKCORE_LIBRARY) # define LIBDTKCORESHARED_EXPORT Q_DECL_EXPORT #else # define LIBDTKCORESHARED_EXPORT Q_DECL_IMPORT #endif #endif #ifdef D_DEPRECATED_CHECK #define D_DECL_DEPRECATED_X(text) Q_DECL_HIDDEN #define D_DECL_DEPRECATED Q_DECL_HIDDEN #else #ifdef __GNUC__ #if __GNUC__ < 13 #define D_DECL_DEPRECATED __attribute__((__deprecated__)) #define D_DECL_DEPRECATED_X(text) __attribute__((__deprecated__(text))) #else #define D_DECL_DEPRECATED Q_DECL_DEPRECATED #define D_DECL_DEPRECATED_X Q_DECL_DEPRECATED_X #endif #else #define D_DECL_DEPRECATED Q_DECL_DEPRECATED #define D_DECL_DEPRECATED_X Q_DECL_DEPRECATED_X #endif #endif #define DTK_VERSION_CHECK(major, minor, patch, build) ((major<<24)|(minor<<16)|(patch<<8)|build) #define DTK_VERSION DTK_VERSION_CHECK(DTK_VERSION_MAJOR, DTK_VERSION_MINOR, DTK_VERSION_PATCH, DTK_VERSION_BUILD) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) extern "C" { int LIBDTKCORESHARED_EXPORT dtkVersion(); const LIBDTKCORESHARED_EXPORT char *dtkVersionString(); } #endif dtkcore-5.7.12/include/log/000077500000000000000000000000001476226660600154645ustar00rootroot00000000000000dtkcore-5.7.12/include/log/LogManager.h000066400000000000000000000024421476226660600176530ustar00rootroot00000000000000// Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd. // SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef LOGMANAGER_H #define LOGMANAGER_H #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DLogManagerPrivate; class LIBDTKCORESHARED_EXPORT DLogManager { Q_DISABLE_COPY(DLogManager) public: static void registerConsoleAppender(); static void registerFileAppender(); static void registerJournalAppender(); static QString getlogFilePath(); /*! * \brief setlogFilePath will change log file path of registerFileAppender * \a logFilePath is the full path of file appender log */ static void setlogFilePath(const QString &logFilePath); static void setLogFormat(const QString &format); private: void initConsoleAppender(); void initRollingFileAppender(); void initJournalAppender(); QString joinPath(const QString &path, const QString &fileName); inline static DLogManager* instance(){ static DLogManager instance; return &instance; } explicit DLogManager(); ~DLogManager(); QScopedPointer d_ptr; Q_DECLARE_PRIVATE(DLogManager) }; DCORE_END_NAMESPACE #endif // LOGMANAGER_H dtkcore-5.7.12/include/settings/000077500000000000000000000000001476226660600165435ustar00rootroot00000000000000dtkcore-5.7.12/include/settings/backend/000077500000000000000000000000001476226660600201325ustar00rootroot00000000000000dtkcore-5.7.12/include/settings/backend/dsettingsdconfigbackend.h000066400000000000000000000017611476226660600251560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include "dsettingsbackend.h" DCORE_BEGIN_NAMESPACE class DSettingsDConfigBackendPrivate; class LIBDTKCORESHARED_EXPORT DSettingsDConfigBackend : public Dtk::Core::DSettingsBackend { Q_OBJECT public: explicit DSettingsDConfigBackend(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); ~DSettingsDConfigBackend() Q_DECL_OVERRIDE; virtual QStringList keys() const Q_DECL_OVERRIDE; virtual QVariant getOption(const QString &key) const Q_DECL_OVERRIDE; protected Q_SLOTS: virtual void doSetOption(const QString &key, const QVariant &value) Q_DECL_OVERRIDE; virtual void doSync() Q_DECL_OVERRIDE; private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), DSettingsDConfigBackend) }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/settings/backend/gsettingsbackend.h000066400000000000000000000016001476226660600236170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include "dsettingsbackend.h" DCORE_BEGIN_NAMESPACE class GSettingsBackendPrivate; class LIBDTKCORESHARED_EXPORT GSettingsBackend: public DSettingsBackend { Q_OBJECT public: explicit GSettingsBackend(DSettings *settings, QObject *parent = nullptr); ~GSettingsBackend(); virtual QStringList keys() const Q_DECL_OVERRIDE; virtual QVariant getOption(const QString &key) const Q_DECL_OVERRIDE; protected Q_SLOTS: virtual void doSetOption(const QString &key, const QVariant &value) Q_DECL_OVERRIDE; virtual void doSync() Q_DECL_OVERRIDE; private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), GSettingsBackend) }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/settings/backend/qsettingbackend.h000066400000000000000000000016131476226660600234520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include "dsettingsbackend.h" DCORE_BEGIN_NAMESPACE class QSettingBackendPrivate; class LIBDTKCORESHARED_EXPORT QSettingBackend : public Dtk::Core::DSettingsBackend { Q_OBJECT public: explicit QSettingBackend(const QString &filepath, QObject *parent = 0); ~QSettingBackend(); virtual QStringList keys() const Q_DECL_OVERRIDE; virtual QVariant getOption(const QString &key) const Q_DECL_OVERRIDE; protected Q_SLOTS: virtual void doSetOption(const QString &key, const QVariant &value) Q_DECL_OVERRIDE; virtual void doSync() Q_DECL_OVERRIDE; private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), QSettingBackend) }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/settings/dsettings.h000066400000000000000000000030631476226660600207220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DSettingsBackend; class DSettingsOption; class DSettingsGroup; class DSettingsPrivate; class LIBDTKCORESHARED_EXPORT DSettings : public QObject { Q_OBJECT public: explicit DSettings(QObject *parent = Q_NULLPTR); ~DSettings(); void setBackend(DSettingsBackend *backend = nullptr); static QPointer fromJson(const QByteArray &json); static QPointer fromJsonFile(const QString &filepath); QJsonObject meta() const; QStringList keys() const; QList> options() const; QPointer option(const QString &key) const; QVariant value(const QString &key) const; QStringList groupKeys() const; QList> groups() const; QPointer group(const QString &key) const; QVariant getOption(const QString &key) const; Q_SIGNALS: void valueChanged(const QString &key, const QVariant &value); public Q_SLOTS: //! //! \brief sync //! WARNING: sync will block void sync() ; void setOption(const QString &key, const QVariant &value); void reset() ; private: void parseJson(const QByteArray &json); void loadValue(); QScopedPointer dd_ptr; Q_DECLARE_PRIVATE_D(qGetPtrHelper(dd_ptr), DSettings) }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/settings/dsettingsbackend.h000066400000000000000000000021511476226660600222270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DSettings; class LIBDTKCORESHARED_EXPORT DSettingsBackend : public QObject { Q_OBJECT public: explicit DSettingsBackend(QObject *parent = Q_NULLPTR): QObject(parent) { connect(this, &DSettingsBackend::sync, this, &DSettingsBackend::doSync, Qt::QueuedConnection); connect(this, &DSettingsBackend::setOption, this, &DSettingsBackend::doSetOption, Qt::QueuedConnection); } virtual ~DSettingsBackend() {} virtual QStringList keys() const = 0; virtual QVariant getOption(const QString &key) const = 0; virtual void doSync() = 0; protected: virtual void doSetOption(const QString &key, const QVariant &value) = 0; Q_SIGNALS: void optionChanged(const QString &key, const QVariant &value); // private signals; Q_SIGNALS: void sync(); void setOption(const QString &key, const QVariant &value); }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/settings/dsettingsgroup.h000066400000000000000000000024571476226660600220050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include "dsettingsoption.h" #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DSettingsGroupPrivate; class LIBDTKCORESHARED_EXPORT DSettingsGroup : public QObject { Q_OBJECT public: explicit DSettingsGroup(QObject *parent = Q_NULLPTR); ~DSettingsGroup(); QPointer parentGroup() const; void setParentGroup(QPointer parentGroup); QString key() const; QString name() const; bool isHidden() const; QPointer childGroup(const QString &groupKey) const; QPointer option(const QString &key) const; QList > childGroups() const; QList > childOptions() const; QList > options() const; static QPointer fromJson(const QString &prefixKey, const QJsonObject &group); private: void parseJson(const QString &prefixKey, const QJsonObject &group); QScopedPointer dd_ptr; Q_DECLARE_PRIVATE_D(qGetPtrHelper(dd_ptr), DSettingsGroup) }; typedef QPointer GroupPtr; DCORE_END_NAMESPACE dtkcore-5.7.12/include/settings/dsettingsoption.h000066400000000000000000000027461476226660600221620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE class DSettingsGroup; class DSettingsOptionPrivate; class LIBDTKCORESHARED_EXPORT DSettingsOption : public QObject { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) public: explicit DSettingsOption(QObject *parent = Q_NULLPTR); ~DSettingsOption(); QPointer parentGroup() const; void setParentGroup(QPointer parentGroup); QString key() const; QString name() const; bool canReset() const; QVariant defaultValue() const; QVariant value() const; QVariant data(const QString &dataType) const; QString viewType() const; bool isHidden() const; static QPointer fromJson(const QString &prefixKey, const QJsonObject &json); Q_SIGNALS: void valueChanged(QVariant value); void dataChanged(const QString &dataType, QVariant value); public Q_SLOTS: void setValue(QVariant value); void setData(const QString &dataType, QVariant value); private: void parseJson(const QString &prefixKey, const QJsonObject &option); QScopedPointer dd_ptr; Q_DECLARE_PRIVATE_D(qGetPtrHelper(dd_ptr), DSettingsOption) }; typedef QPointer OptionPtr; DCORE_END_NAMESPACE dtkcore-5.7.12/include/util/000077500000000000000000000000001476226660600156605ustar00rootroot00000000000000dtkcore-5.7.12/include/util/dabstractunitformatter.h000066400000000000000000000020561476226660600226270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DABSTRACTUNITFORMATTER_H #define DABSTRACTUNITFORMATTER_H #include "dtkcore_global.h" #include #include DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DAbstractUnitFormatter { public: DAbstractUnitFormatter(); ~DAbstractUnitFormatter(); protected: virtual int unitMax() const = 0; virtual int unitMin() const = 0; virtual uint unitConvertRate(int unitId) const = 0; virtual qreal unitValueMax(int unitId) const { return unitConvertRate(unitId) - 1; } virtual qreal unitValueMin(int unitId) const { Q_UNUSED(unitId); return 1; } virtual QString unitStr(int unitId) const = 0; public: qreal formatAs(qreal value, int currentUnit, const int targetUnit) const; QPair format(const qreal value, const int unit) const; QList> formatAsUnitList(const qreal value, int unit) const; }; DCORE_END_NAMESPACE #endif // DABSTRACTUNITFORMATTER_H dtkcore-5.7.12/include/util/dasync.h000066400000000000000000000412551476226660600173210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DASYNC_H #define DASYNC_H #include #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE #define GUARDED_BY(...) #define D_THREAD_IN_MAIN() (qApp->instance() && qApp->instance()->thread() == QThread::currentThread()) // TODO: 添加 DtkCorePrivate 到 dtkcore_global.h namespace DtkCorePrivate { // 本类是继承实现的,只有子类方法是安全的,暂不对外提供接口 template class DSafeQueue : public QQueue { public: inline void enqueue(const T &t) { QMutexLocker lkc(&m_mtx); QQueue::enqueue(t); } inline T dequeue() { QMutexLocker lkc(&m_mtx); return QQueue::dequeue(); } inline int size() { QMutexLocker lkc(&m_mtx); return QQueue::size(); } inline T &head() { QMutexLocker lkc(&m_mtx); return QQueue::head(); } inline const T &head() const { QMutexLocker lkc(&m_mtx); return QQueue::head(); } private: mutable QMutex m_mtx; }; // 内部使用,不对外提供接口 class MainWorker : public QObject { Q_OBJECT std::function m_handle; std::function m_handleProxy; std::function m_handleV; std::function m_handleVProxy; bool m_dasyncDestroyed = false; char __padding[7]; public: void setDAsyncDestroyed() { m_dasyncDestroyed = true; } bool dasyncDestroyed() { return m_dasyncDestroyed; } public: MainWorker(QObject *parent = nullptr) : QObject(parent) { // Ensure that QApplication is initialized Q_ASSERT(qApp->instance() && qApp->instance()->thread()); moveToThread(qApp->instance()->thread()); bool isStartInMain = D_THREAD_IN_MAIN(); QObject::connect(this, &MainWorker::sigRunInMain, this, &MainWorker::slotRunInMain, isStartInMain ? Qt::AutoConnection : Qt::BlockingQueuedConnection); QObject::connect(this, &MainWorker::sigRunInMainVoid, this, &MainWorker::slotRunInMainVoid, isStartInMain ? Qt::AutoConnection : Qt::BlockingQueuedConnection); } // 1. handle arg is non void template typename std::enable_if::value>::type setHandle(FUNC &&func) { m_handle = [&](void *arg) { DSafeQueue *q = static_cast *>(arg); while (q && q->size()) { // 这里是 then 回调真正执行到的地方 func(q->dequeue()); } }; m_handleProxy = [this](void *arg) { if (m_handle) { m_handle(arg); } }; } // 2. handle arg is void template typename std::enable_if::value>::type setHandle(FUNC &&func) { m_handleV = [&](void) { // 这里是 then 回调真正执行到的地方 func(); }; m_handleVProxy = [this](void) { if (m_handleV) { m_handleV(); } }; } Q_SIGNALS: void sigRunInMain(void *arg); void sigRunInMainVoid(); public Q_SLOTS: void slotRunInMain(void *arg) { Q_ASSERT(D_THREAD_IN_MAIN()); if (m_handleProxy && !m_dasyncDestroyed) { m_handleProxy(arg); } } void slotRunInMainVoid(void) { Q_ASSERT(D_THREAD_IN_MAIN()); if (m_handleVProxy && !m_dasyncDestroyed) { m_handleVProxy(); } } }; } // namespace DtkCorePrivate class DAsyncState : public QObject { Q_OBJECT public: explicit DAsyncState(QObject *parent = nullptr) noexcept : QObject(parent) { } enum AsyncTaskState { NotReady = 0x00, // initial state Ready = 0x02, // deffered = false Running = 0x04, // thread started Pending = Ready | Running, // condition wait Cancel = 0x08, // set thread canceled WaitFinished = 0x10, // wiaitForFinished Finished = 0x20, // thread exit Forever = 0x30, // TODO: DAsync::post execute forever }; Q_DECLARE_FLAGS(AsyncTaskStatus, AsyncTaskState) }; // Template classes not supported by Q_OBJECT, so class MainWorker is independent template class D_DECL_DEPRECATED DAsync : public QObject { class Helper; std::mutex m_mtxIn; std::condition_variable m_cvIn; std::mutex m_mtxForWaitTask; std::condition_variable m_cvForWaitTask; class Guard { DAsync *m_as; // 如果 DAsync 已经析构了,工作线程还没结束 // DAsync 中的有些数据就不能在 guard 的析构里面访问了 bool m_dasDestructed = false; public: bool destructed() { return m_dasDestructed; } void setDestructed() { m_dasDestructed = true; } public: explicit Guard(DAsync *as) noexcept : m_as(as) { m_as->m_status.setFlag(DAsyncState::Ready); m_as->m_status.setFlag(DAsyncState::Finished, false); // 防止重入 } ~Guard() { if (destructed()) { return; } m_as->m_threadGuard = nullptr; m_as->m_status.setFlag(DAsyncState::Finished); m_as->m_status.setFlag(DAsyncState::Ready, false); // 防止重入 if (m_as->m_status.testFlag(DAsyncState::WaitFinished)) { m_as->m_cvForWaitTask.notify_one(); } setPending(false); } void setPending(bool isPending) { if (!destructed()) { m_as->m_status.setFlag(DAsyncState::Pending, isPending); } } }; Guard *m_threadGuard = nullptr; /* * m_QueueIn 的作用是存储 PostData 传进来的数据 * m_QueueOut 的作用是将 post 处理完的结果暂存起来然后传入到 then 中 * 在 emitHelper 中调用 post 进来的任务,然后将结果传到主线程中处理 * 数据传递使用 void * 做转换,对于复合类型避免了使用 qRegisterMetaType */ template struct DataQueueType { DtkCorePrivate::DSafeQueue m_queue; }; template struct DataQueueType::value>::type> { }; using DataInQueue = DataQueueType; using DataOutQueue = DataQueueType; // Queue 中处理完的结果经由 m_QueueIn 变量暂存,然后经由 signal、slot 传给 then 中的回调函数做参数 DataInQueue m_QueueIn; DataOutQueue m_QueueOut; // 存储不同类型的输入函数 template struct FuncType { }; template struct FuncType::value>::type, typename std::enable_if::value>::type> { std::function cbp; }; template struct FuncType::value>::type, typename std::enable_if::value>::type> { std::function cbp; }; template struct FuncType::value>::type, typename std::enable_if::value>::type> { std::function cbp; }; template struct FuncType::value>::type, typename std::enable_if::value>::type> { std::function cbp; }; std::mutex m_mtxFunc; FuncType m_func GUARDED_BY(m_mtxFunc); DAsyncState::AsyncTaskStatus m_status; public: explicit DAsync(QObject *parent = nullptr) noexcept : QObject(parent) , m_func({nullptr}) , m_status(DAsyncState::NotReady) { m_mainWorker = new DtkCorePrivate::MainWorker(); m_helper = new Helper(this, this); } ~DAsync() { if (m_threadGuard) { m_threadGuard->setDestructed(); } m_status.setFlag(DAsyncState::Cancel); if (m_status.testFlag(DAsyncState::Pending)) { m_cvIn.notify_one(); } if (m_mainWorker) { m_mainWorker->setDAsyncDestroyed(); m_mainWorker->deleteLater(); m_mainWorker = nullptr; } } private: // 1. input void & emit void template typename std::enable_if::value && std::is_void::value>::type emitHelper() { m_func.cbp(); Q_EMIT m_mainWorker->sigRunInMainVoid(); } // 2. input non void & emit non void template typename std::enable_if::value && !std::is_void::value>::type emitHelper() { m_QueueOut.m_queue.enqueue(m_func.cbp(m_QueueIn.m_queue.dequeue())); Q_EMIT m_mainWorker->sigRunInMain(static_cast(&(m_QueueOut.m_queue))); } // 3. input non void & emit void template typename std::enable_if::value && std::is_void::value>::type emitHelper() { m_func.cbp(m_QueueIn.m_queue.dequeue()); Q_EMIT m_mainWorker->sigRunInMainVoid(); } // 4. input void & emit non void template typename std::enable_if::value && !std::is_void::value>::type emitHelper() { m_QueueOut.m_queue.enqueue(m_func.cbp()); Q_EMIT m_mainWorker->sigRunInMain(static_cast(&(m_QueueOut.m_queue))); } public: void startUp() { if (m_status.testFlag(DAsyncState::Cancel)) { return; } m_helper->start(); } void cancelAll() { m_status.setFlag(DAsyncState::Cancel); if (m_status.testFlag(DAsyncState::Pending)) { m_cvIn.notify_one(); } } bool isFinished() { return m_status.testFlag(DAsyncState::Finished); } /* * 不能在 QTimer 中使用 waitForFinished,防止阻塞主线程 * 也不能在主线程执行前使用 waitForFinished() * 它的默认参数为 true,等同于 waitForFinished(false) + * cancelAll, 如果调用了后者, 会一直阻塞等待任务,直到 * cancelAll 被调用之后 waitForFinished 才会在任务完成完 * 成后退出,此时就可以删除DAsync了。最好的管理方式还是采用 * QObject 的内存托管。主线程中使用,可以采用托管的方式, * 任务结束只要调用 cancelAll + isFinished 轮询判断就行了, * DAsync 的工作线程就会在完成后自动退出。 */ void waitForFinished(bool cancelAllWorks = true) { Q_ASSERT(!D_THREAD_IN_MAIN()); if (cancelAllWorks) { cancelAll(); } if (!m_status.testFlag(DAsyncState::Finished)) { if (m_status.testFlag(DAsyncState::Pending)) { m_cvIn.notify_one(); } m_status.setFlag(DAsyncState::WaitFinished); std::unique_lock lck(m_mtxForWaitTask); m_cvForWaitTask.wait(lck); } } // 输入数据不是 void 类型则依赖于 m_QueueIn template typename std::enable_if::value, Helper *>::type post(FUNC &&func) { m_func.cbp = std::forward(func); if (m_postProxy) { return m_helper; } m_postProxy = [this]() { std::thread thread([this] { if (m_status.testFlag(DAsyncState::Cancel)) { return; } Guard guard(this); m_threadGuard = &guard; std::unique_lock lck(m_mtxIn); while (true) { while (!m_status.testFlag(DAsyncState::Ready) || !m_QueueIn.m_queue.size()) { guard.setPending(true); // 定时查询 flag,防止睡死的情况发生 m_cvIn.wait_for(lck, std::chrono::milliseconds(200)); if (guard.destructed() || m_status.testFlag(DAsyncState::Cancel)) { return; } } guard.setPending(false); while (m_func.cbp && m_QueueIn.m_queue.size()) { emitHelper(); } } }); thread.detach(); }; return m_helper; } template typename std::enable_if::value, Helper *>::type post(FUNC &&func) { { std::lock_guard lckFunc(m_mtxFunc); m_func.cbp = std::forward(func); } if (m_postProxy) { return m_helper; } m_postProxy = [this]() { std::thread thread([this] { if (m_status.testFlag(DAsyncState::Cancel)) { return; } Guard guard(this); m_threadGuard = &guard; std::unique_lock lck(m_mtxIn); while (true) { if (!m_status.testFlag(DAsyncState::Ready)) { guard.setPending(true); // 定时查询 flag,防止睡死的情况发生 m_cvIn.wait_for(lck, std::chrono::milliseconds(200)); if (guard.destructed() || m_status.testFlag(DAsyncState::Cancel)) { return; } } guard.setPending(false); if (m_func.cbp) { std::lock_guard lckFunc(m_mtxFunc); emitHelper(); m_func.cbp = nullptr; // reset } } }); thread.detach(); }; return m_helper; } // only support DAsync template typename std::enable_if::value>::type postData(const InputType &data) { if (Q_UNLIKELY(!m_status.testFlag(DAsyncState::Cancel))) { m_QueueIn.m_queue.enqueue(data); if (m_status.testFlag(DAsyncState::Pending)) { m_cvIn.notify_one(); } } } private: std::function m_postProxy; class Helper : public QObject { DAsync *m_async; public: explicit Helper(DAsync *async, QObject *parent = nullptr) noexcept : QObject(parent) , m_async(async) { } template Helper *then(FUNC &&func) { m_async->m_mainWorker->template setHandle(std::forward(func)); return this; } // 仅启动,非阻塞 void start(bool immediately = true) { if (m_async->m_postProxy) { m_async->m_postProxy(); } if (!immediately) { m_async->m_status.setFlag(DAsyncState::Ready, false); } else { m_async->m_status.setFlag(DAsyncState::Ready); if (m_async->m_status.testFlag(DAsyncState::Pending)) { m_async->m_cvIn.notify_one(); } } } }; Helper *m_helper = nullptr; DtkCorePrivate::MainWorker *m_mainWorker = nullptr; }; DCORE_END_NAMESPACE #endif // DASYNC_H dtkcore-5.7.12/include/util/ddbusextendedabstractinterface.h000066400000000000000000000057501476226660600242670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 Jolla Ltd. // // SPDX-License-Identifier: LGPL-2.1-or-later #ifndef DBUSEXTENDEDABSTRACTINTERFACE_H #define DBUSEXTENDEDABSTRACTINTERFACE_H #include "dtkcore_global.h" #include #include class QDBusPendingCallWatcher; DCORE_BEGIN_NAMESPACE class DDBusExtendedPendingCallWatcher; class LIBDTKCORESHARED_EXPORT DDBusExtendedAbstractInterface : public QDBusAbstractInterface { Q_OBJECT public: virtual ~DDBusExtendedAbstractInterface(); Q_PROPERTY(bool sync READ sync WRITE setSync) inline bool sync() const { return m_sync; } void setSync(bool sync); void setSync(bool sync, bool autoStart); Q_PROPERTY(bool useCache READ useCache WRITE setUseCache) inline bool useCache() const { return m_useCache; } inline void setUseCache(bool useCache) { m_useCache = useCache; } void getAllProperties(); inline QDBusError lastExtendedError() const { return m_lastExtendedError; } public Q_SLOTS: void startServiceProcess(); protected: DDBusExtendedAbstractInterface( const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent); void connectNotify(const QMetaMethod &signal); void disconnectNotify(const QMetaMethod &signal); QVariant internalPropGet(const char *propname, void *propertyPtr); void internalPropSet(const char *propname, const QVariant &value, void *propertyPtr); Q_SIGNALS: void serviceValidChanged(const bool valid) const; void serviceStartFinished(const quint32 ret) const; void propertyChanged(const QString &propertyName, const QVariant &value); void propertyInvalidated(const QString &propertyName); void asyncPropertyFinished(const QString &propertyName); void asyncSetPropertyFinished(const QString &propertyName); void asyncGetAllPropertiesFinished(); private Q_SLOTS: void onPropertiesChanged(const QString &interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties); void onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); void onAsyncPropertyFinished(QDBusPendingCallWatcher *w); void onAsyncSetPropertyFinished(QDBusPendingCallWatcher *w); void onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *watcher); void onStartServiceProcessFinished(QDBusPendingCallWatcher *w); private: QVariant asyncProperty(const QString &propertyName); void asyncSetProperty(const QString &propertyName, const QVariant &value); static QVariant demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error); bool m_sync; bool m_useCache; QDBusPendingCallWatcher *m_getAllPendingCallWatcher; QDBusError m_lastExtendedError; QString m_dbusOwner; bool m_propertiesChangedConnected; }; DCORE_END_NAMESPACE #endif /* DBUSEXTENDEDABSTRACTINTERFACE_H */ dtkcore-5.7.12/include/util/ddbusinterface.h000066400000000000000000000021571476226660600210200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include "dtkcore_global.h" #include DCORE_BEGIN_NAMESPACE class DDBusInterfacePrivate; // Imported since 5.6.3 class DDBusInterface : public QDBusAbstractInterface { Q_OBJECT public: explicit DDBusInterface(const QString &service, const QString &path, const QString &interface, const QDBusConnection &connection = QDBusConnection::sessionBus(), QObject *parent = nullptr); virtual ~DDBusInterface() override; bool serviceValid() const; QString suffix() const; void setSuffix(const QString &suffix); QVariant property(const char *propName); void setProperty(const char *propName, const QVariant &value); Q_SIGNALS: void serviceValidChanged(const bool valid) const; private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(DDBusInterface) Q_DISABLE_COPY(DDBusInterface) }; DCORE_END_NAMESPACE dtkcore-5.7.12/include/util/ddbussender.h000066400000000000000000000045301476226660600203350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DDBUSSENDER_H #define DDBUSSENDER_H #include "dtkcore_global.h" #include #include #include #include #include class LIBDTKCORESHARED_EXPORT DDBusData { public: DDBusData(); QDBusPendingCall asyncCallWithArguments(const QString &method, const QVariantList &arguments, const QString &iface = QString()); QString service; QString path; QString interface; QString queryName; QDBusConnection connection; }; class LIBDTKCORESHARED_EXPORT DDBusCaller { friend class DDBusSender; public: QDBusPendingCall call(); template DDBusCaller arg(const T &argument); private: explicit DDBusCaller(const QString &method, std::shared_ptr data); private: std::shared_ptr m_dbusData; QString m_methodName; QVariantList m_arguments; }; template DDBusCaller DDBusCaller::arg(const T &argument) { m_arguments << QVariant::fromValue(argument); return *this; } class LIBDTKCORESHARED_EXPORT DDBusProperty { friend class DDBusSender; public: QDBusPendingCall get(); template QDBusPendingCall set(const T &value); private: explicit DDBusProperty(const QString &property, std::shared_ptr data); private: std::shared_ptr m_dbusData; QString m_propertyName; }; template QDBusPendingCall DDBusProperty::set(const T &value) { QVariantList args{QVariant::fromValue(m_dbusData->interface), QVariant::fromValue(m_propertyName), QVariant::fromValue(QDBusVariant(value))}; return m_dbusData->asyncCallWithArguments(QStringLiteral("Set"), args, QStringLiteral("org.freedesktop.DBus.Properties")); } class LIBDTKCORESHARED_EXPORT DDBusSender { public: explicit DDBusSender(); DDBusSender service(const QString &service); DDBusSender interface(const QString &interface); DDBusSender path(const QString &path); DDBusCaller method(const QString &method); DDBusProperty property(const QString &property); static DDBusSender system(); private: DDBusSender type(const QDBusConnection::BusType busType); private: std::shared_ptr m_dbusData; }; #endif // DDBUSSENDER_H dtkcore-5.7.12/include/util/ddisksizeformatter.h000066400000000000000000000014671476226660600217560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DISKSIZEFORMATTER_H #define DISKSIZEFORMATTER_H #include "dabstractunitformatter.h" DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DDiskSizeFormatter : public DAbstractUnitFormatter { public: DDiskSizeFormatter(); enum DiskUnits { B, K, M, G, T, }; QString unitStr(int unitId) const override; DDiskSizeFormatter rate(int rate); protected: int unitMin() const override { return B; } int unitMax() const override { return T; } uint unitConvertRate(int unitId) const override { Q_UNUSED(unitId); return m_rate; } private: int m_rate = 1000; }; DCORE_END_NAMESPACE #endif // DISKSIZEFORMATTER_H dtkcore-5.7.12/include/util/dexportedinterface.h000066400000000000000000000015241476226660600217120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DEXPORTEDINTERFACE_H #define DEXPORTEDINTERFACE_H #include #include #include #include DCORE_BEGIN_NAMESPACE namespace DUtil { class DExportedInterfacePrivate; class LIBDTKCORESHARED_EXPORT DExportedInterface : public QObject, public DObject { Q_OBJECT public: explicit DExportedInterface(QObject *parent = nullptr); ~DExportedInterface(); void registerAction(const QString &action, const QString &description, const std::function handler = nullptr); virtual QVariant invoke(const QString &action, const QString ¶meters) const; private: D_DECLARE_PRIVATE(DExportedInterface) }; } DCORE_END_NAMESPACE #endif dtkcore-5.7.12/include/util/dfileservices.h000066400000000000000000000032661476226660600206670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILESERVICES_H #define DFILESERVICES_H #include #include DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DFileServices { public: static bool showFolder(QString localFilePath, const QString &startupId = QString()); static bool showFolders(const QList localFilePaths, const QString &startupId = QString()); static bool showFolder(QUrl url, const QString &startupId = QString()); static bool showFolders(const QList urls, const QString &startupId = QString()); static bool showFileItemPropertie(QString localFilePath, const QString &startupId = QString()); static bool showFileItemProperties(const QList localFilePaths, const QString &startupId = QString()); static bool showFileItemPropertie(QUrl url, const QString &startupId = QString()); static bool showFileItemProperties(const QList urls, const QString &startupId = QString()); static bool showFileItem(QString localFilePath, const QString &startupId = QString()); static bool showFileItems(const QList localFilePaths, const QString &startupId = QString()); static bool showFileItem(QUrl url, const QString &startupId = QString()); static bool showFileItems(const QList urls, const QString &startupId = QString()); static bool trash(QString localFilePath); static bool trash(const QList localFilePaths); static bool trash(QUrl urlstartupId); static bool trash(const QList urls); static QString errorMessage(); }; DCORE_END_NAMESPACE #endif // DFILESERVICES_H dtkcore-5.7.12/include/util/dnotifysender.h000066400000000000000000000017711476226660600207140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DNOTIFYSENDER_H #define DNOTIFYSENDER_H #include "dtkcore_global.h" #include #include DCORE_BEGIN_NAMESPACE namespace DUtil { struct DNotifyData; class LIBDTKCORESHARED_EXPORT DNotifySender { public: DNotifySender(const QString &summary); DNotifySender appName(const QString &appName = QString()); DNotifySender appIcon(const QString &appIcon = QString()); DNotifySender appBody(const QString &appBody = QString()); DNotifySender replaceId(const uint replaceId = 0); DNotifySender timeOut(const int timeOut = -1); DNotifySender actions(const QStringList &actions = QStringList()); DNotifySender hints(const QVariantMap &hints = QVariantMap()); QDBusPendingCall call(); private: std::shared_ptr m_dbusData; }; } // namespace DUtil DCORE_END_NAMESPACE #endif // DNOTIFYSENDER_H dtkcore-5.7.12/include/util/dpinyin.h000066400000000000000000000015421476226660600175050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPINYIN_H #define DPINYIN_H #include #include DCORE_BEGIN_NAMESPACE // without polyphonic support QString LIBDTKCORESHARED_EXPORT Chinese2Pinyin(const QString& words); //!< @~english enum ToneStyle - pinyin tone style enum ToneStyle { TS_NoneTone, /*!< @~english pinyin without tone */ TS_Tone, /*!< @~english pinyin tone, default style in dictory file*/ TS_ToneNum, /*!< @~english pinyin tone number */ }; // support polyphonic QStringList LIBDTKCORESHARED_EXPORT pinyin(const QString& words, ToneStyle ts = TS_Tone, bool *ok = nullptr); // support polyphonic QStringList LIBDTKCORESHARED_EXPORT firstLetters(const QString& words); DCORE_END_NAMESPACE #endif // DPINYIN_H dtkcore-5.7.12/include/util/drecentmanager.h000066400000000000000000000012001476226660600210010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DRECENTMANAGER_H #define DRECENTMANAGER_H #include "dtkcore_global.h" #include DCORE_BEGIN_NAMESPACE struct LIBDTKCORESHARED_EXPORT DRecentData { QString appName; QString appExec; QString mimeType; }; class LIBDTKCORESHARED_EXPORT DRecentManager { public: static bool addItem(const QString &uri, DRecentData &data); static void removeItem(const QString &target); static void removeItems(const QStringList &list); }; DCORE_END_NAMESPACE #endif // DRECENTMANAGER_H dtkcore-5.7.12/include/util/dtextencoding.h000066400000000000000000000035571476226660600207020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTEXTENCODING_H #define DTEXTENCODING_H #include #include #include DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DTextEncoding { public: static QByteArray detectTextEncoding(const QByteArray &content); static QByteArray detectFileEncoding(const QString &fileName, bool *isOk = nullptr); static bool convertTextEncoding(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding = QByteArray(), QString *errString = nullptr); static bool convertTextEncodingEx(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding = QByteArray(), QString *errString = nullptr, int *convertedBytes = nullptr); static bool convertFileEncoding(const QString &fileName, const QByteArray &toEncoding, const QByteArray &fromEncoding = QByteArray(), QString *errString = nullptr); static bool convertFileEncodingTo(const QString &fromFile, const QString &toFile, const QByteArray &toEncoding, const QByteArray &fromEncoding = QByteArray(), QString *errString = nullptr); }; DCORE_END_NAMESPACE #endif // DTEXTENCODING_H dtkcore-5.7.12/include/util/dthreadutils.h000066400000000000000000000272431476226660600205350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2020 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTHREADUTILS_H #define DTHREADUTILS_H #include #include #include #include #include #include #include #if DTK_VERSION >= DTK_VERSION_CHECK(6, 0, 0, 0) #include #include #include #endif DCORE_BEGIN_NAMESPACE #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) namespace DThreadUtil { typedef std::function FunctionType; class LIBDTKCORESHARED_EXPORT FunctionCallProxy : public QObject { Q_OBJECT public: explicit FunctionCallProxy(QThread *thread); static void proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun); Q_SIGNALS: void callInLiveThread(QSemaphore *s, QPointer target, FunctionType *func); }; template class LIBDTKCORESHARED_EXPORT _TMP { public: inline static ReturnType runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function fun) { ReturnType result; FunctionType proxyFun = [&result, &fun] () { result = fun(); }; FunctionCallProxy::proxyCall(s, thread, target, proxyFun); return result; } template inline static typename std::enable_if::value, ReturnType>::type runInThread(QSemaphore *s, QThread *thread, T *, std::function fun) { return runInThread(s, thread, static_cast(nullptr), fun); } }; template <> class LIBDTKCORESHARED_EXPORT _TMP { public: inline static void runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function fun) { FunctionCallProxy::proxyCall(s, thread, target, fun); } template inline static typename std::enable_if::value, void>::type runInThread(QSemaphore *s, QThread *thread, T *, std::function fun) { return runInThread(s, thread, static_cast(nullptr), fun); } }; template inline auto runInThread(QSemaphore *s, QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...)) { return _TMP::runInThread(s, thread, target, std::bind(fun, std::forward(args)...)); } template inline auto runInThread(QSemaphore *s, QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...)) { return runInThread(s, thread, nullptr, fun, std::forward(args)...); } template inline typename QtPrivate::FunctionPointer::ReturnType runInThread(QSemaphore *s, QThread *thread, QObject *target, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { return _TMP::ReturnType>::runInThread(s, thread, target, std::bind(fun, obj, std::forward(args)...)); } template inline typename QtPrivate::FunctionPointer::ReturnType runInThread(QSemaphore *s, QThread *thread, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { return _TMP::ReturnType>::runInThread(s, thread, obj, std::bind(fun, obj, std::forward(args)...)); } template inline auto runInThread(QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...)) { QSemaphore s; return runInThread(&s, thread, target, fun, std::forward(args)...); } template inline auto runInThread(QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...)) { return runInThread(thread, nullptr, fun, std::forward(args)...); } template inline typename QtPrivate::FunctionPointer::ReturnType runInThread(QThread *thread, T *target, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { QSemaphore s; return runInThread(&s, thread, target, obj, fun, std::forward(args)...); } template inline typename QtPrivate::FunctionPointer::ReturnType runInThread(QThread *thread, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { return runInThread(thread, obj, obj, fun, std::forward(args)...); } template inline auto runInMainThread(QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...)) { if (!QCoreApplication::instance()) { return fun(std::forward(args)...); } return runInThread(QCoreApplication::instance()->thread(), target, fun, std::forward(args)...); } template inline auto runInMainThread(Fun fun, Args&&... args) -> decltype(fun(args...)) { return runInMainThread(nullptr, fun, std::forward(args)...); } template inline typename QtPrivate::FunctionPointer::ReturnType runInMainThread(T *target, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { if (!QCoreApplication::instance()) { return (obj->*fun)(std::forward(args)...); } return runInThread(QCoreApplication::instance()->thread(), target, obj, fun, std::forward(args)...); } template inline typename QtPrivate::FunctionPointer::ReturnType runInMainThread(typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { return runInMainThread(obj, obj, fun, std::forward(args)...); } } #else class LIBDTKCORESHARED_EXPORT DThreadUtils final { friend class Caller; public: explicit DThreadUtils(QThread *thread); ~DThreadUtils(); static DThreadUtils &gui(); QThread *thread() const noexcept; template inline auto run(QObject *context,typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) { return call(context, fun, *obj, std::forward(args)...); } template inline auto run(typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) { if constexpr (std::is_base_of::Object>::value) { return call(obj, fun, *obj, std::forward(args)...); } else { return call(static_cast(nullptr), fun, *obj, std::forward(args)...); } } template inline QFuture, Args...>> run(QObject *context, Func fun, Args &&...args) { return call(context, fun, std::forward(args)...); } template inline QFuture, Args...>> run(Func fun, Args &&...args) { return call(static_cast(nullptr), fun, std::forward(args)...); } template inline decltype(auto) exec(T &&...args) { auto future = run(std::forward(args)...); if (!thread()->isRunning()) { qWarning() << "The target thread is not running, maybe lead to deadlock."; } future.waitForFinished(); if constexpr (std::is_same_v>) { return; } else { return future.result(); } } private: class AbstractCallEvent : public QEvent { public: AbstractCallEvent(QEvent::Type type) : QEvent(type) { } virtual void call() = 0; }; template class Q_DECL_HIDDEN CallEvent : public AbstractCallEvent { using FunInfo = QtPrivate::FunctionPointer>; using ReturnType = std::invoke_result_t, Args...>; public: CallEvent(QEvent::Type type, Func &&fun, Args &&...args) : AbstractCallEvent(type) , function(std::forward(fun)) , arguments(std::forward(args)...) { } QEvent *clone() const override { return nullptr; } void call() override { if (promise.isCanceled()) { return; } if (contextChecker == context) { promise.start(); #ifndef QT_NO_EXCEPTIONS try { #endif if constexpr (std::is_void_v) { std::apply(function, arguments); } else { promise.addResult(std::apply(function, arguments)); } #ifndef QT_NO_EXCEPTIONS } catch (...) { promise.setException(std::current_exception()); } #endif promise.finish(); } else { promise.start(); promise.setException(std::make_exception_ptr(std::runtime_error("The context object is destroyed."))); promise.finish(); } } Func function; const std::tuple arguments; QPromise promise; QObject *context{nullptr}; QPointer contextChecker; }; template inline auto call(QObject *context, Func fun, Args &&...args) { using FuncInfo = QtPrivate::FunctionPointer>; using ReturnType = std::invoke_result_t, Args...> ; if constexpr (FuncInfo::IsPointerToMemberFunction) { static_assert(std::is_same_v::Car>, typename FuncInfo::Object>, "The obj and function are not compatible."); static_assert( QtPrivate::CheckCompatibleArguments::Cdr, typename FuncInfo::Arguments>::value, "The args and function are not compatible."); } else if constexpr (FuncInfo::ArgumentCount != -1) { static_assert(QtPrivate::CheckCompatibleArguments, typename FuncInfo::Arguments>::value, "The args and function are not compatible."); } else { // for lambda and impl operator() static_assert(std::is_invocable_r_v, "The callable object can't invoke with supplied args"); } QPromise promise; auto future = promise.future(); if (Q_UNLIKELY(QThread::currentThread() == m_thread)) { promise.start(); if constexpr (std::is_void_v) { std::invoke(fun, std::forward(args)...); } else { promise.addResult(std::invoke(fun, std::forward(args)...)); } promise.finish(); } else { auto event = new CallEvent(eventType, std::move(fun), std::forward(args)...); event->promise = std::move(promise); event->context = context; event->contextChecker = context; QCoreApplication::postEvent(ensureThreadContextObject(), event); } return future; } QObject *ensureThreadContextObject(); static inline QEvent::Type eventType; QThread *m_thread; QAtomicPointer threadContext; }; #endif // version macro end DCORE_END_NAMESPACE #endif // protect macro end dtkcore-5.7.12/include/util/dtimedloop.h000066400000000000000000000031041476226660600201670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTIMEDLOOP_H #define DTIMEDLOOP_H #include #include #include DCORE_BEGIN_NAMESPACE class DObject; class DTimedLoopPrivate; class DTimedLoop : public QEventLoop, public DObject { Q_OBJECT public: explicit DTimedLoop() noexcept; explicit DTimedLoop(QObject *parent) noexcept; ~DTimedLoop(); // 如果是 isRunning 则返回从开始到现在的 exec 执行时间,否则返回上次运行的时间 int runningTime(); void setTimeDump(bool flag = true); void exit(int returnCode = 0); // 方式1:不传定时时间,如果不退出就一直执行,配合 exit 使用 // 方式2:传入durationMs 参数的是定时执行的,也能调用 exit 提前退出 // 如果传入了 executionName 就会为本次执行设置一个名字,会输出到 log // 在执行结束将会打印 exec 的执行时间,可以用 setTimeDump 控制其是否打印 int exec(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); int exec(int durationMs, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); int exec(const QString &executionName, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); int exec(int durationMs, const QString &executionName, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); private: Q_DISABLE_COPY(DTimedLoop) D_DECLARE_PRIVATE(DTimedLoop) }; DCORE_END_NAMESPACE #endif // DTIMEDLOOP_H dtkcore-5.7.12/include/util/dtimeunitformatter.h000066400000000000000000000013661476226660600217650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTIMEUNITFORMATTER_H #define DTIMEUNITFORMATTER_H #include "dtkcore_global.h" #include "dabstractunitformatter.h" DCORE_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DTimeUnitFormatter : public DAbstractUnitFormatter { public: DTimeUnitFormatter(); enum TimeUnits { Seconds, Minute, Hour, Day, }; QString unitStr(int unitId) const override; protected: int unitMax() const override { return Day; } int unitMin() const override { return Seconds; } uint unitConvertRate(int unitId) const override; }; DCORE_END_NAMESPACE #endif // DTIMEUNITFORMATTER_H dtkcore-5.7.12/include/util/dutil.h000066400000000000000000000076201476226660600171570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include #include #include #include #include #include #include namespace DUtil { template inline void TimerSingleShot(int msec, Func1 slot) { #if QT_VERSION >= 0x050500 QTimer::singleShot(msec, slot); #else QTimer *timer = new QTimer; timer->setSingleShot(true); timer->setInterval(msec); timer->moveToThread(qApp->thread()); QObject::connect(timer, &QTimer::timeout, slot); QObject::connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater); if (QThread::currentThread() == qApp->thread()) { timer->start(); } else { QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection); } #endif } template void SecureErase(T *p, size_t size) { static_assert(std::is_standard_layout::value && std::is_trivially_destructible::value, "try to erase content of raw pointer, but type T isn't suitable"); std::memset(p, 0, size); } template void SecureErase(T &obj) { static_assert(std::is_default_constructible::value, "container's value type must have a default constructor."); for (typename T::iterator i = obj.begin(); i != obj.end(); ++i) { *i = typename T::value_type{}; } } inline QString escapeToObjectPath(const QString &str) { if (str.isEmpty()) { return "_"; } auto ret = str; QRegularExpression re{R"([^a-zA-Z0-9])"}; auto matcher = re.globalMatch(ret); while (matcher.hasNext()) { auto replaceList = matcher.next().capturedTexts(); replaceList.removeDuplicates(); for (const auto &c : replaceList) { auto hexStr = QString::number(static_cast(c.front().toLatin1()), 16); ret.replace(c, QString{R"(_%1)"}.arg(hexStr)); } } return ret; } inline QString unescapeFromObjectPath(const QString &str) { auto ret = str; for (int i = 0; i < str.size(); ++i) { if (str[i] == '_' && i + 2 < str.size()) { auto hexStr = str.mid(i + 1, 2); ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16))); i += 2; } } return ret; } inline QString getAppIdFromAbsolutePath(const QString &path) { static QString desktopSuffix{u8".desktop"}; const auto &appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); if (!path.endsWith(desktopSuffix) || !std::any_of(appDirs.cbegin(), appDirs.constEnd(), [&path](const QString &dir) { return path.startsWith(dir); })) { return {}; } auto tmp = path.chopped(desktopSuffix.size()); auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts); auto location = std::find(components.cbegin(), components.cend(), "applications"); if (location == components.cend()) { return {}; } auto appId = QStringList{location + 1, components.cend()}.join('-'); return appId; } inline QStringList getAbsolutePathFromAppId(const QString &appId) { auto components = appId.split('-', Qt::SkipEmptyParts); auto appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); QStringList ret; for (const auto &dirPath : appDirs) { auto currentDir = dirPath; for (auto it = components.cbegin(); it != components.cend(); ++it) { auto currentName = QStringList{it, components.cend()}.join('-') + QString{".desktop"}; QDir dir{currentDir}; if (dir.exists(currentName)) { ret.append(dir.filePath(currentName)); } currentDir.append(QDir::separator() + *it); } } return ret; } } dtkcore-5.7.12/include/util/dvtablehook.h000066400000000000000000000340521476226660600203370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DVTABLEHOOK_H #define DVTABLEHOOK_H #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE #ifndef QT_DEBUG inline Q_LOGGING_CATEGORY(vtableHook, "dtk.vtableHook", QtInfoMsg); #else inline Q_LOGGING_CATEGORY(vtableHook, "dtk.vtableHook"); #endif class LIBDTKCORESHARED_EXPORT DVtableHook { public: static inline quintptr toQuintptr(const void *ptr) { return *(quintptr*)ptr; } static inline int getVtableSize(quintptr **obj) { quintptr *begin = *obj; while (true) { if ((int64_t)*begin == 0 or (int64_t)*begin < QSysInfo::WordSize) // offset will grater than 8 bytes(64 bit) break; ++begin; } return begin - *obj + 2; // for offset and rtti info } static inline quintptr *getVtableOfObject(const void *obj) { return *(quintptr**)obj; } template static quintptr *getVtableOfClass() { QByteArray vtable_symbol(typeid(T).name()); vtable_symbol.prepend("_ZTV"); quintptr *vfptr_t1 = reinterpret_cast(resolve(vtable_symbol.constData())); return vfptr_t1 ? adjustToEntry(vfptr_t1) : nullptr; } static int getDestructFunIndex(quintptr **obj, std::function destoryObjFun); static constexpr const QObject *getQObject(...) { return nullptr;} static constexpr const QObject *getQObject(const QObject *obj) { return obj;} static void autoCleanVtable(const void *obj); static bool ensureVtable(const void *obj, std::function destoryObjFun); static bool hasVtable(const void *obj); static void resetVtable(const void *obj); static quintptr resetVfptrFun(const void *obj, quintptr functionOffset); static quintptr originalFun(const void *obj, quintptr functionOffset); static bool forceWriteMemory(void *adr, const void *data, size_t length); static QFunctionPointer resolve(const char *symbol); template class OverrideDestruct : public T { ~OverrideDestruct() override;}; template struct CheckCompatibleArguments { enum { value = false }; }; template struct CheckCompatibleArguments { enum { value = true }; }; template static bool overrideVfptrFun(quintptr *vfptr_t1, Fun1 fun1, quintptr *vfptr_t2, Fun2 fun2, bool forceWrite) { typedef QtPrivate::FunctionPointer FunInfo1; typedef QtPrivate::FunctionPointer FunInfo2; //compilation error if the arguments does not match. Q_STATIC_ASSERT_X((CheckCompatibleArguments::value), "Function1 and Function2 arguments are not compatible."); Q_STATIC_ASSERT_X((CheckCompatibleArguments, QtPrivate::List>::value), "Function1 and Function2 return type are not compatible.."); //! ({code}) in the form of a code is to eliminate - Wstrict - aliasing build warnings quintptr fun1_offset = toQuintptr(&fun1); quintptr fun2_offset = toQuintptr(&fun2); if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) return false; quintptr *vfun = vfptr_t1 + fun1_offset / sizeof(quintptr); // if the fun2 is not virtual function if (fun2_offset <= UINT_LEAST16_MAX) { fun2_offset = *(vfptr_t2 + fun2_offset / sizeof(quintptr)); } if (forceWrite) return forceWriteMemory(vfun, &fun2_offset, sizeof(fun2_offset)); *vfun = fun2_offset; return true; } template static bool overrideVfptrFun(const typename QtPrivate::FunctionPointer::Object *t1, Fun1 fun1, const typename QtPrivate::FunctionPointer::Object *t2, Fun2 fun2) { typedef QtPrivate::FunctionPointer FunInfo1; // 检查析构函数是否为虚 class OverrideDestruct : public FunInfo1::Object { ~OverrideDestruct() override;}; //TODO: we can use std::has_virtual_destructor if (!ensureVtable((void*)t1, std::bind(&_destory_helper, t1))) { return false; } quintptr *vfptr_t1 = getVtableOfObject(t1); quintptr *vfptr_t2 = getVtableOfObject(t2); bool ok = overrideVfptrFun(vfptr_t1, fun1, vfptr_t2, fun2, false); if (!ok) { // 恢复旧环境 resetVtable(t1); } return ok; } template static bool overrideVfptrFun(Fun1 fun1, const typename QtPrivate::FunctionPointer::Object *t2, Fun2 fun2) { quintptr *vfptr_t1 = getVtableOfClass(); if (!vfptr_t1) { abort(); } quintptr *vfptr_t2 = getVtableOfObject(t2); return overrideVfptrFun(vfptr_t1, fun1, vfptr_t2, fun2, true); } template static bool overrideVfptrFun(Fun1 fun1, const typename QtPrivate::FunctionPointer::Object *t2, Fun2 fun2) { typedef QtPrivate::FunctionPointer FunInfo1; return overrideVfptrFun(fun1, t2, fun2); } template struct FunctionPointer { }; template struct FunctionPointer { typedef QtPrivate::List Arguments; }; template struct FunctionPointer { typedef QtPrivate::List Arguments; }; template static typename std::enable_if::ArgumentCount >= 0, bool>::type overrideVfptrFun(quintptr *vfptr_t1, Fun1 fun1, Fun2 fun2, bool forceWrite) { typedef QtPrivate::FunctionPointer FunInfo1; typedef QtPrivate::FunctionPointer FunInfo2; Q_STATIC_ASSERT(!FunInfo2::IsPointerToMemberFunction); //compilation error if the arguments does not match. Q_STATIC_ASSERT_X((CheckCompatibleArguments::Arguments, typename FunInfo2::Arguments>::value), "Function1 and Function2 arguments are not compatible."); Q_STATIC_ASSERT_X((CheckCompatibleArguments, QtPrivate::List>::value), "Function1 and Function2 return type are not compatible.."); //! ({code}) in the form of a code is to eliminate - Wstrict - aliasing build warnings quintptr fun1_offset = toQuintptr(&fun1); quintptr fun2_offset = toQuintptr(&fun2); if (fun1_offset > UINT_LEAST16_MAX) return false; quintptr *vfun = vfptr_t1 + fun1_offset / sizeof(quintptr); if (forceWrite) return forceWriteMemory(vfun, &fun2_offset, sizeof(fun2_offset)); *vfun = fun2_offset; return true; } template struct StdFunWrap {}; template struct StdFunWrap { typedef std::function StdFunType; static inline StdFunType fun(StdFunType f, bool check = true) { static StdFunType fun = f; static bool initialized = false; if (initialized && check) qCWarning(vtableHook, "The StdFunWrap is dirty! Don't use std::bind(use lambda functions)."); initialized = true; return fun; } static Ret call(Obj *o, Args... args) { return fun(call, false)(o, std::forward(args)...); } }; template struct StdFunWrap : StdFunWrap{}; template static inline typename std::enable_if::ArgumentCount == -1, bool>::type overrideVfptrFun(quintptr *vfptr_t1, Fun1 fun1, Fun2 fun2, bool forceWrite) { typedef QtPrivate::FunctionPointer FunInfo1; const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount::Arguments>::Value; Q_STATIC_ASSERT_X((FunctorArgumentCount >= 0), "Function1 and Function2 arguments are not compatible."); const int Fun2ArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0; typedef typename QtPrivate::FunctorReturnType::Arguments, Fun2ArgumentCount>::Value>::Value Fun2ReturnType; Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), "Function1 and Function2 return type are not compatible."); StdFunWrap::fun(fun2); return overrideVfptrFun(vfptr_t1, fun1, StdFunWrap::call, forceWrite); } /*! * \fn template static bool overrideVfptrFun(const typename QtPrivate::FunctionPointer::Object *t1, Fun1 fun1, Fun2 fun2) * * \note 重载多继承类中的多个虚函数时,fun1务必标记成一个类名的函数。否则可能出现内存泄露的情况 * \note 例如 class A 继承于 B,C,D,当需要重载B中的foo1,C中的foo2时,以下函数的fun1需要统一标记为&A::foo1和&A::foo2 * \note 因为如果分开写为&B::foo1和&C::foo2的话,指针转换内部会记录多张虚表,重载多份析构函数,可能导致最开始的部分无法正常析构! */ template static bool overrideVfptrFun(const typename QtPrivate::FunctionPointer::Object *t1, Fun1 fun1, Fun2 fun2) { typedef QtPrivate::FunctionPointer FunInfo1; // 检查析构函数是否为虚 class OverrideDestruct : public FunInfo1::Object { ~OverrideDestruct() override;}; if (!ensureVtable((void*)t1, std::bind(&_destory_helper, t1))) { return false; } bool ok = overrideVfptrFun(getVtableOfObject(t1), fun1, fun2, false); if (!ok) { // 恢复旧环境 resetVtable(t1); } return true; } template static bool overrideVfptrFun(Fun1 fun1, Fun2 fun2) { quintptr *vfptr_t1 = getVtableOfClass(); if (!vfptr_t1) { abort(); } return overrideVfptrFun(vfptr_t1, fun1, fun2, true); } template static bool overrideVfptrFun(Fun1 fun1, Fun2 fun2) { typedef QtPrivate::FunctionPointer FunInfo1; return overrideVfptrFun(fun1, fun2); } template static bool resetVfptrFun(const typename QtPrivate::FunctionPointer::Object *obj, Fun1 fun) { return resetVfptrFun((void*)obj, toQuintptr(&fun)) > 0; } template static Fun originalFun(const typename QtPrivate::FunctionPointer::Object *obj, Fun fun) { quintptr o_fun = originalFun((void*)obj, toQuintptr(&fun)); return *reinterpret_cast(o_fun); } template static typename QtPrivate::FunctionPointer::ReturnType callOriginalFun(typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) { quintptr fun_offset = toQuintptr(&fun); class _ResetVFun { public: ~_ResetVFun() { *(vfptr + offset / sizeof(quintptr)) = oldFun; } quintptr *vfptr = nullptr; quint16 offset = 0; quintptr oldFun = 0; }; _ResetVFun rvf; rvf.vfptr = *(quintptr**)(obj); rvf.offset = fun_offset; rvf.oldFun = DVtableHook::resetVfptrFun((void*)obj, fun_offset); if (!rvf.oldFun) { qCWarning(vtableHook) << "Reset the function failed, object: " << obj; abort(); } // call return (obj->*fun)(std::forward(args)...); } private: static bool copyVtable(quintptr **obj); static bool clearGhostVtable(const void *obj); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) Q_DECL_DEPRECATED static bool isFinalClass(quintptr *obj); Q_DECL_DEPRECATED static quintptr **adjustThis(quintptr *obj); #endif template static T adjustToTop(T obj) // vtableTop: vtable start address, Usually refers to offset_to_top { // this function should'n be called when entry is parent entry using fundamentalType = typename std::remove_cv::type>::type; return obj - static_cast(2); // vtable start address = vtable entry - 2 } template static T adjustToEntry(T obj) // vtableEntry: is located after rtti in the virtual table { // this function should'n be called when entry is parent entry using fundamentalType = typename std::remove_cv::type>::type; return obj + static_cast(2); // vtable entry = vtable start address + 2 } template static void _destory_helper(const T *obj) { delete obj; } static QMap objToOriginalVfptr; static QMap objToGhostVfptr; static QMap objDestructFun; }; DCORE_END_NAMESPACE #endif // DVTABLEHOOK_H dtkcore-5.7.12/linglong.yaml000066400000000000000000000007541476226660600157630ustar00rootroot00000000000000package: id: dtkcore name: dtkcore kind: lib version: 5.6.3 description: | Deepin Tool Kit Core Devel library \ DtkCore is base devel library of Deepin Qt/C++ applications. base: id: org.deepin.base/23.0.0 depends: - id: qtbase/5.15.7 - id: dtkcommon/5.6.0.1 - id: gsettings-qt/0.3.1.1 source: kind: local variables: extra_args: | -DBUILD_EXAMPLES=OFF \ -DBUILD_DOCS=OFF \ -DBUILD_TESTING=OFF \ -DDTK_VERSION=${VERSION} build: kind: cmake dtkcore-5.7.12/misc/000077500000000000000000000000001476226660600142135ustar00rootroot00000000000000dtkcore-5.7.12/misc/DtkCoreConfig.cmake.in000066400000000000000000000016471476226660600203130ustar00rootroot00000000000000@PACKAGE_INIT@ if(UNIX AND NOT APPLE) set(LINUX TRUE) endif() include(CMakeFindDependencyMacro) find_dependency(Qt@QT_VERSION_MAJOR@Core) find_dependency(Qt@QT_VERSION_MAJOR@Xml) find_dependency(Dtk@DTK_VERSION_MAJOR@Log) if (LINUX) find_dependency(Qt@QT_VERSION_MAJOR@DBus) endif() find_dependency(Dtk@DTK_VERSION_MAJOR@DConfig) include(${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@CoreTargets.cmake) set(DtkCore_LIBRARIES Dtk@DTK_VERSION_MAJOR@::Core) get_target_property(DtkCore_INCLUDE_DIRS Dtk@DTK_VERSION_MAJOR@::Core INTERFACE_INCLUDE_DIRECTORIES) get_target_property(DtkCore_LIBRARY_DIRS Dtk@DTK_VERSION_MAJOR@::Core INTERFACE_LINK_DIRECTORIES) set(DtkCore_TOOL_DIRS "@PACKAGE_TOOL_INSTALL_DIR@") check_required_components(DtkCore) # Keep deprecated variables for compatibility set(DTKCORE_INCLUDE_DIRS ${DtkCore_INCLUDE_DIRS}) set(DTKCORE_TOOL_DIRS ${DtkCore_TOOL_DIRS}) add_definitions(-DQT_MESSAGELOGCONTEXT) dtkcore-5.7.12/misc/dtk_install_dconfig.prf000066400000000000000000000062611476226660600207320ustar00rootroot00000000000000# This prf file is used to deploy files that dconfig's meta and override configure. # # get variable `$$DSG_DATA_DIR` 's value, it’s consistent with class DConfigFile code. isEmpty(DSG_DATA_DIR) { isEmpty(PREFIX) { DSG_DATA_DIR=/usr/share/dsg } else { DSG_DATA_DIR=$$PREFIX/share/dsg } } # deploy some `meta` 's configure. # # files - deployed files. # base - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. # appid - working for the app, if it's empty, depending on `TEMPLATE`. # commonid - working for common, if it's empyt, depending on `TEMPLATE`. # # e.g: # dconfig_example.files += \ # $$PWD/configs/dconf-example.json \ # $$PWD/configs/a/dconf-example.json # dconfig_example.base = $$PWD/configs # dconfig_example.appid = $$TARGET # # dconfig_example2.files += $$PWD/configs/a/dconf-example.json # # DCONFIG_META_FILES += dconfig_example dconfig_example2 # for(metaitem, DCONFIG_META_FILES) { eval(dconfig_meta_$${metaitem}.files = $$eval($${metaitem}.files)) eval(dconfig_meta_$${metaitem}.base = $$eval($${metaitem}.base)) isEmpty($${metaitem}.appid) { is_common_configuration=true isEmpty($${metaitem}.commonid) { equals(TEMPLATE, app) { eval(dconfig_meta_$${metaitem}.path = $$DSG_DATA_DIR/configs/$$TARGET/) is_common_configuration=false } } if ($$is_common_configuration) { eval(dconfig_meta_$${metaitem}.path = $$DSG_DATA_DIR/configs) } } else { eval(dconfig_meta_$${metaitem}.path = $$DSG_DATA_DIR/configs/$$eval($${metaitem}.appid)) } INSTALLS += dconfig_meta_$${metaitem} } # deploy some `meta` 's override configure. # # configuration for the `meta_name` 's override configure. # # files - deployed files. # base - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. # appid - working for the app, if it's empty, working for all app. # meta_name - override for the meta configure. # # e.g : # dconfig_example.files += \ # $$PWD/configs/dconf-example.override.json \ # $$PWD/configs/a/dconf-example.override.a.json # dconfig_example.base = $$PWD/configs # dconfig_example.meta_name = example # dconfig_example.appid = $$TARGET # # dconfig_example2.files += $$PWD/configs/a/dconf-example.override.a.json # dconfig_example2.meta_name = example2 # # DCONFIG_OVERRIDE_FILES += dconfig_example dconfig_example2 # for(overrideitem, DCONFIG_OVERRIDE_FILES) { eval(dconfig_override_$${overrideitem}.files = $$eval($${overrideitem}.files)) eval(dconfig_override_$${overrideitem}.base = $$eval($${overrideitem}.base)) isEmpty($${overrideitem}.meta_name) : error("Please set meta_name for the override configuration." $${overrideitem}) isEmpty($${overrideitem}.appid) { eval(dconfig_override_$${overrideitem}.path = $$DSG_DATA_DIR/configs/overrides/$$eval($${overrideitem}.meta_name)) } else { eval(dconfig_override_$${overrideitem}.path = $$DSG_DATA_DIR/configs/overrides/$$eval($${overrideitem}.appid)/$$eval($${overrideitem}.meta_name)) } INSTALLS += dconfig_override_$${overrideitem} } dtkcore-5.7.12/misc/dtkcore.pc.in000066400000000000000000000005751476226660600166060ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@LIBRARY_INSTALL_DIR@ includedir=${prefix}/@INCLUDE_INSTALL_DIR@ Name: dtk@DTK_VERSION_MAJOR@core Description: Deepin Tool Kit dtkcore header files Version: @CMAKE_PROJECT_VERSION@ Libs: -L${libdir} -ldtk@DTK_VERSION_MAJOR@core Cflags: -I${includedir} -DQT_MESSAGELOGCONTEXT Requires: dtk@DTK_VERSION_MAJOR@log dtkcore-5.7.12/misc/qt_lib_dtkcore.pri.in000066400000000000000000000011541476226660600203220ustar00rootroot00000000000000QT.dtkcore.VERSION = @CMAKE_PROJECT_VERSION@ QT.dtkcore.MAJOR_VERSION = @PROJECT_VERSION_MAJOR@ QT.dtkcore.MINOR_VERSION = @PROJECT_VERSION_MINOR@ QT.dtkcore.PATCH_VERSION = @PROJECT_VERSION_PATCH@ QT.dtkcore.name = dtkcore QT.dtkcore.module = dtk@DTK_VERSION_MAJOR@core QT.dtkcore.tools = @CMAKE_INSTALL_PREFIX@/@TOOL_INSTALL_DIR@ QT.dtkcore.libs = @CMAKE_INSTALL_PREFIX@/@LIBRARY_INSTALL_DIR@ QT.dtkcore.includes = @CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@ QT.dtkcore.frameworks = QT.dtkcore.depends = core dbus xml dtklog QT.dtkcore.module_config = v2 ltcg QT.dtkcore.DEFINES += QT_MESSAGELOGCONTEXT QT_MODULES += dtkcore-5.7.12/rpm/000077500000000000000000000000001476226660600140565ustar00rootroot00000000000000dtkcore-5.7.12/rpm/dtkcore.spec000066400000000000000000000040051476226660600163640ustar00rootroot00000000000000Name: dtkcore Version: 5.5.18 Release: 1%{?dist} Summary: Deepin tool kit core modules License: LGPLv3+ URL: https://github.com/linuxdeepin/dtkcore %if 0%{?fedora} Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz %else Source0: %{name}-%{version}.orig.tar.xz %endif BuildRequires: dtkcommon-devel BuildRequires: gcc-c++ BuildRequires: annobin BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(gsettings-qt) BuildRequires: gtest-devel BuildRequires: uchardet-devel BuildRequires: libicu-devel # since f30 Obsoletes: deepin-tool-kit <= 0.3.3 Obsoletes: deepin-tool-kit-devel <= 0.3.3 Obsoletes: dtksettings <= 0.1.7 Obsoletes: dtksettings-devel <= 0.1.7 %description Deepin tool kit core modules. %package devel Summary: Development package for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} Requires: dtkcommon-devel Requires: qt5-qtbase-devel%{?_isa} %description devel Header files and libraries for %{name}. %prep %autosetup -p1 %build # help find (and prefer) qt5 utilities, e.g. qmake, lrelease export PATH=%{_qt5_bindir}:$PATH %qmake_qt5 PREFIX=%{_prefix} \ DTK_VERSION=%{version} \ LIB_INSTALL_DIR=%{_libdir} \ BIN_INSTALL_DIR=%{_libexecdir}/dtk5 \ TOOL_INSTALL_DIR=%{_libexecdir}/dtk5 %make_build %install %make_install INSTALL_ROOT=%{buildroot} %files %doc README.md %license LICENSE %{_libdir}/lib%{name}.so.5* %dir %{_libexecdir}/dtk5/ %{_libexecdir}/dtk5/dtk-settings %{_libexecdir}/dtk5/dtk-license.py %{_libexecdir}/dtk5/dtk-translate.py %{_libexecdir}/dtk5/deepin-os-release %{_prefix}/bin/qdbusxml2cpp-fix %files devel %doc doc/Specification.md %{_includedir}/libdtk-*/ %{_qt5_archdatadir}/mkspecs/modules/*.pri %{_libdir}/cmake/DtkCore/ %{_libdir}/cmake/DtkCMake/ %{_libdir}/cmake/DtkTools/ %{_libdir}/pkgconfig/dtkcore.pc %{_libdir}/lib%{name}.so %changelog * Thu Jun 11 2020 uoser - 5.2.2.3 - Update to 5.2.2.3 dtkcore-5.7.12/src/000077500000000000000000000000001476226660600140475ustar00rootroot00000000000000dtkcore-5.7.12/src/CMakeLists.txt000066400000000000000000000113711476226660600166120ustar00rootroot00000000000000#cmake_minimum_required(VERSION 3.5) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(Dtk${DTK_VERSION_MAJOR}Log REQUIRED) if(LINUX) find_package(PkgConfig REQUIRED) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus) if("${QT_VERSION_MAJOR}" STREQUAL "5") pkg_check_modules(QGSettings REQUIRED IMPORTED_TARGET gsettings-qt) #Dtk6 removed. endif() endif() find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Xml) find_package(DtkBuildHelper REQUIRED) # start text encoding find_package(ICU REQUIRED COMPONENTS uc) pkg_check_modules(uchardet REQUIRED uchardet) # end text encoding # start base include(base/base.cmake) # end base # start dci include(dci/dci.cmake) #end dci #start filesystem include(filesystem/filesystem.cmake) #end filesystem # start log include(log/log.cmake) #end log # start settings include(settings/settings.cmake) #end settings #start utils include(util/util.cmake) #end utils #GLOB include(glob.cmake) #endGLOG if(LINUX) add_library(${LIB_NAME} SHARED ${base_SRCS} ${dci_SRCS} ${filesystem_SRCS} ${log_SRCS} ${settings_SRC} ${utils_SRC} ${glob_SRC} ) target_link_libraries( ${LIB_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Xml Dtk${DTK_VERSION_MAJOR}::Log ) target_link_libraries(${LIB_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::CorePrivate ) if("${QT_VERSION_MAJOR}" STREQUAL "5") target_link_libraries(${LIB_NAME} PRIVATE PkgConfig::QGSettings ) endif() else() add_library(${LIB_NAME} SHARED ${base_SRCS} ${dci_SRCS} ${filesystem_SRCS} ${log_SRCS} ${settings_SRC} ${utils_SRC} ${glob_SRC} ) target_link_libraries( ${LIB_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Xml ) target_link_libraries(${LIB_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::CorePrivate ) if("${QT_VERSION_MAJOR}" STREQUAL "5") target_link_libraries(${LIB_NAME} PRIVATE PkgConfig::QGSettings ) endif() endif() set_target_properties(${LIB_NAME} PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR} EXPORT_NAME Core ) target_compile_definitions(${LIB_NAME} PUBLIC PREFIX="${DSG_PREFIX_PATH}" DSYSINFO_PREFIX="${DSYSINFO_PREFIX}" ) target_compile_definitions(${LIB_NAME} PRIVATE LIBDTKCORE_LIBRARY ) target_include_directories(${LIB_NAME} PRIVATE ${uchardet_INCLUDE_DIRS} ) target_include_directories(${LIB_NAME} PUBLIC $ $ $ $ $ $ $ $ $ $ ) target_include_directories(${LIB_NAME} INTERFACE $ ) target_link_directories(${LIB_NAME} INTERFACE $ $ ) set(EnableCov CACHE BOOL OFF) if (EnableCov) dtk_setup_code_coverage(${LIB_NAME}) endif() dtk_check_and_add_definitions(${LIB_NAME} DEFS OS_VERSION_TEST_FILE LSB_RELEASE_TEST_FILE OS_RELEASE_TEST_FILE DEEPIN_VERSION_TEST_FILE ) set(TOINSTALLBASE ../include/base/dobject.h ../include/base/dsingleton.h ../include/base/private/dobject_p.h ../include/base/derror.h ../include/base/dexpected.h ) install(FILES ${TOINSTALLBASE} DESTINATION "${INCLUDE_INSTALL_DIR}") install(FILES ${LOG_HEADER} DESTINATION "${INCLUDE_INSTALL_DIR}") install(FILES ${SETTINGS_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}") install(FILES ${UTILS_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}") install(DIRECTORY ../include/dci/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") install(DIRECTORY ../include/DtkCore/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") install(DIRECTORY ../include/filesystem/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") install(DIRECTORY ../include/global/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") install(TARGETS ${LIB_NAME} EXPORT ${DtkCore}Targets DESTINATION ${LIBRARY_INSTALL_DIR}) install(EXPORT ${DtkCore}Targets FILE ${DtkCore}Targets.cmake NAMESPACE Dtk${DTK_VERSION_MAJOR}:: DESTINATION ${CONFIG_CMAKE_INSTALL_DIR} ) dtkcore-5.7.12/src/base/000077500000000000000000000000001476226660600147615ustar00rootroot00000000000000dtkcore-5.7.12/src/base/base.cmake000066400000000000000000000005431476226660600166770ustar00rootroot00000000000000set(base_SRCS ${CMAKE_CURRENT_LIST_DIR}/../../include/base/dobject.h ${CMAKE_CURRENT_LIST_DIR}/../../include/base/private/dobject_p.h ${CMAKE_CURRENT_LIST_DIR}/../../include/base/dsingleton.h ${CMAKE_CURRENT_LIST_DIR}/../../include/base/dexpected.h ${CMAKE_CURRENT_LIST_DIR}/../../include/base/derror.h ${CMAKE_CURRENT_LIST_DIR}/dobject.cpp ) dtkcore-5.7.12/src/base/dobject.cpp000066400000000000000000000126721476226660600171070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dobject.h" #include "base/private/dobject_p.h" DCORE_BEGIN_NAMESPACE DObjectPrivate::DObjectPrivate(DObject *qq) : q_ptr(qq) { } DObjectPrivate::~DObjectPrivate() { } /*! \headerfile \inmodule dtkcore \brief 一些宏的定义. */ /*! \class Dtk::Core::DObject \inmodule dtkcore \brief deepin-tool-kit 中所有公开类的祖先类. 通过和 D_DECLARE_PRIVATE 、D_DECLARE_PUBLIC 等宏的配合方便派生类中实现 D-Point 结构。虽然 QObject 中已经有了这样的实现结构,但是没有 办法在不使用 Qt 私有模块的情况下,在 DTK 库中达到同样的目的。D-Point 结构由“公共接口类” 和“私有数据类”两部分组成,在 DTK 中,DObjectPrivate 是所有数据类的祖先类。在这种结构下, 只有 DObject 这个基类中定了一个指向于私有数据类的对象指针,派生类中不会也不应该再定义任何 成员变量,派生类中需要添加数据成员时,可以继承 DObjectPrivate,将新的成员变量放到私有类中 例子: a.h \code class APrivate; class A : public DObject { D_DECLARE_PRIVATE(A) public: A(); int test() const; protected: A(APrivate &dd, DObject *parent = nullptr); }; \endcode a.cpp \code class APrivate : public DObjectPrivate { public: APrivate(A *qq) : DObjectPrivate(qq) { } D_DECLARE_PUBLIC(A) // 此处添加数据成员 int data; }; A::A() : DObject(*new APrivate(this)) { } int test() const { D_D(A); return d->data; } A::A(APrivate &dd, DObject *parent) : DObject(dd, parent) { } \endcode 一般来讲,DObject 只会用在 DTK 库中定义的类,对于使用 DTK 库的应用程序来说不用关心它的存在 \sa {https://wiki.qt.io/D-Pointer/zh}{类的 D-Point 结构} */ /*! \brief 只有在不需要数据成员的派生类中才会使用 \a parent 父类指针 */ DObject::DObject(DObject * /*parent = nullptr*/) { } /*! \brief 在派生类中比较常用的构造函数 \a dd 私有类对象 */ DObject::DObject(DObjectPrivate &dd, DObject * /*parent = nullptr*/): d_d_ptr(&dd) { } DObject::~DObject() { } /*! \macro D_DECLARE_PRIVATE(Class) \relates Dtk::Core::DObject \brief 这个宏一定要放到类的私有区域,它定义了 d_func() 这个函数用于返回私有类的对象, 这个对象只应该在类的内部使用,另外将私有类声明为公开类的友元类。 \a Class 公开类的类名 \sa D_DECLARE_PUBLIC D_D D_DC */ /*! \macro D_DECLARE_PUBLIC(Class) \relates Dtk::Core::DObject \brief 这个宏用于私有类中,它定义了 q_func() 这个函数用于返回公开类的对象,另外将公开类 声明为私有类的友元类。 \a Class 公开类的类名 \sa D_DECLARE_PRIVATE D_Q D_QC */ /*! \macro D_D(Class) \relates Dtk::Core::DObject \brief 这个宏用于公开类中,它定义了一个名字为 d 的变量存储 d_func() 的返回值。用于在公开 类中需要访问私有类的数据成员的函数中。 \a Class 公开类的类名 \sa D_DECLARE_PRIVATE D_DC */ /*! \macro D_DC(Class) \relates Dtk::Core::DObject \brief 同 D_D,用在公开类加了 const 修饰符的成员函数中。 \a Class 公开类的类名 \sa D_DECLARE_PRIVATE D_D */ /*! \macro D_Q(Class) \relates Dtk::Core::DObject \brief 这个宏用于私有类中,它定义了一个名字为 q 的变量存储 q_func() 的返回值。用于在私有 类中需要调用公开类的成员函数时。 \a Class 公开类的类名 \sa D_DECLARE_PUBLIC D_QC */ /*! \macro D_QC(Class) \relates Dtk::Core::DObject \brief 同 D_Q,用在私有类加了 const 修饰符的成员函数中。 \a Class 公开类的类名 \sa D_DECLARE_PUBLIC D_Q */ /*! \macro D_PRIVATE_SLOT(Func) \relates Dtk::Core::DObject \brief 同 Q_PRIVATE_SLOT,用在继承了 QObject 的公开类中,在公开类中定一个槽函数,且函数 必须在私有类中有实现。用这个方式定义的槽函数无法被直接调用,只能用于 QObject::connect 使用 SIGNAL 和 SLOT 的方式连接信号,或者使用 QMetaObject::invokeMethod 调用。 一般来讲,这个槽函数应该只在类内部使用,外界不应该通过任何方式来调用它。 例子: a.h \code class APrivate; class A : public DObject { D_DECLARE_PRIVATE(A) public: A(); protected: A(APrivate &dd, DObject *parent = nullptr); private: D_PRIVATE_SLOT(void _q_testSlot() const) }; \endcode a.cpp \code class APrivate : public DObjectPrivate { public: D_DECLARE_PUBLIC(A) APrivate(A *qq) : DObjectPrivate(qq) { QTimer *timer = new QTimer(); QObject::connect(timer, SIGNAL(timeout()), qq, SLOT(_q_testSlot())); timer->start(1000); } void _q_testSlot() const { qDebug() << "slot"; } }; A::A() : DObject(*new APrivate(this)) { } A::A(APrivate &dd, DObject *parent) : DObject(dd, parent) { } \#include "moc_a.cpp" \endcode \a Func 槽函数的完整签名 \note 添加或更新私有槽之后需要重新手动调用 qmake \sa D_DECLARE_PUBLIC D_Q */ DCORE_END_NAMESPACE dtkcore-5.7.12/src/dbus/000077500000000000000000000000001476226660600150045ustar00rootroot00000000000000dtkcore-5.7.12/src/dbus/dbus.cmake000066400000000000000000000016761476226660600167550ustar00rootroot00000000000000set(dbus_SRCS) set_source_files_properties( ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml PROPERTIES NO_NAMESPACE ON CLASSNAME DSGConfig ) if("${QT_VERSION_MAJOR}" STREQUAL "6") qt_add_dbus_interface(dbus_SRCS ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml configmanager_interface ) else() qt5_add_dbus_interface(dbus_SRCS ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml configmanager_interface ) endif() set_source_files_properties( ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.Manager.xml PROPERTIES NO_NAMESPACE ON CLASSNAME DSGConfigManager ) if("${QT_VERSION_MAJOR}" STREQUAL "6") qt_add_dbus_interface(dbus_SRCS ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.Manager.xml manager_interface ) else() qt5_add_dbus_interface(dbus_SRCS ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.Manager.xml manager_interface ) endif() dtkcore-5.7.12/src/dbus/org.desktopspec.ConfigManager.Manager.xml000066400000000000000000000033571476226660600247200ustar00rootroot00000000000000 ' dtkcore-5.7.12/src/dbus/org.desktopspec.ConfigManager.xml000066400000000000000000000012151476226660600233360ustar00rootroot00000000000000 dtkcore-5.7.12/src/dci/000077500000000000000000000000001476226660600146065ustar00rootroot00000000000000dtkcore-5.7.12/src/dci/dci.cmake000066400000000000000000000003371476226660600163520ustar00rootroot00000000000000set(dci_SRCS ${CMAKE_CURRENT_LIST_DIR}/../../include/dci/ddcifile.h ${CMAKE_CURRENT_LIST_DIR}/ddcifile.cpp ${CMAKE_CURRENT_LIST_DIR}/private/ddcifileengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/ddcifileengine.cpp ) dtkcore-5.7.12/src/dci/ddcifile.cpp000066400000000000000000000544101476226660600170610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddcifile.h" #include "private/ddcifileengine_p.h" #ifndef DTK_NO_PROJECT #include #else #define D_D(class) #define D_DC(class) #endif #include #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE #define MAGIC "DCI" #define MAGIC_SIZE 4 #define VERSION_SIZE 1 #define FILE_COUNT_SIZE 3 #define FILE_META_SIZE 72 #define FILE_TYPE_SIZE 1 #define FILE_NAME_SIZE 63 #define FILE_DATA_SIZE 8 #define FILE_TYPE_FILE DDciFile::FileType::File #define FILE_TYPE_DIR DDciFile::FileType::Directory #define FILE_TYPE_SYMLINK DDciFile::FileType::Symlink #ifdef QT_DEBUG Q_LOGGING_CATEGORY(logDF, "dtk.dci.file") #else Q_LOGGING_CATEGORY(logDF, "dtk.dci.file", QtInfoMsg) #endif class DDciFilePrivate #ifndef DTK_NO_PROJECT : public DObjectPrivate #endif { public: DDciFilePrivate(DDciFile *qq) #ifndef DTK_NO_PROJECT : DObjectPrivate(qq) { #else { Q_UNUSED(qq) #endif } ~DDciFilePrivate(); void setErrorString(const QString &message); void load(const QString &fileName); void load(const QByteArray &data); QString errorMessage; struct Node { qint8 type = DDciFile::UnknowFile; QString name; Node *parent = nullptr; QVector children; // for directory QByteArray data; // for file ~Node() { qDeleteAll(children); } QString path() const { QString p = name; Node *current = parent; while (current) { p.prepend(current->name + "/"); current = current->parent; } return p; } QString linkPath() const { const QString &path = QString::fromUtf8(data); QStringView pathView{path}; if (pathView.startsWith('/')) return path; // 转为绝对路径 auto pNode = parent; int pathStart = 0; while (pathStart < pathView.size()) { if (pathView.mid(pathStart, 3) == QLatin1String("../")) { pathStart += 3; pNode = pNode->parent; if (!pNode) return QString(); } else if (pathView.mid(pathStart, 2) == QLatin1String("./")) { pathStart += 2; } else { break; } } Q_ASSERT(pNode); return pNode->path() + QLatin1Char('/') + path.mid(pathStart); } }; qint64 writeMetaDataForNode(QIODevice *device, Node *node, qint64 dataSize) const; qint64 writeDataForNode(QIODevice *device, Node *node) const; qint64 writeNode(QIODevice *device, Node *node) const; Node *mkNode(const QString &filePath); void removeNode(Node *node); void copyNode(const Node *from, Node *to); bool loadDirectory(Node *directory, const QByteArray &data, qint64 &begin, qint64 end, QHash &pathToNode); // 按标准中规定的文件排序计算此 name 在这个列表中的位置 static int getOrderedIndexOfNodeName(const decltype(Node::children) &list, const QString &name); qint8 version = 0; QScopedPointer root; QHash pathToNode; QByteArray rawData; }; DDciFilePrivate::~DDciFilePrivate() { } void DDciFilePrivate::setErrorString(const QString &message) { qCDebug(logDF, "%s", qPrintable(message)); errorMessage = message; } void DDciFilePrivate::load(const QString &fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { setErrorString(file.errorString()); return; } return load(file.readAll()); } void DDciFilePrivate::load(const QByteArray &data) { // check magic if (!data.startsWith("DCI")) { setErrorString(QString("Expect value is \"DCI\", " "but actually value is \"%1\"") .arg(QString::fromLatin1(data.left(3)))); return; } qint8 version = data.at(MAGIC_SIZE); if (version != 1) { setErrorString(QString("Not supported version: %1").arg(version)); return; } char fileCountData[4]; int fileCountOffset = MAGIC_SIZE + VERSION_SIZE; memcpy(fileCountData, data.constData() + fileCountOffset, FILE_COUNT_SIZE); fileCountData[3] = 0; int fileCount = qFromLittleEndian(fileCountData); if (fileCount < 0) { setErrorString(QString("Invalid file count: %1").arg(fileCount)); return; } qint64 offset = MAGIC_SIZE + VERSION_SIZE + FILE_COUNT_SIZE; Node *root = new Node; root->type = FILE_TYPE_DIR; root->parent = nullptr; QHash pathToNode; if (!loadDirectory(root, data, offset, data.size() - 1, pathToNode) || fileCount != root->children.count()) { delete root; return; } this->version = version; this->root.reset(root); this->pathToNode = pathToNode; this->pathToNode["/"] = root; // Node 中保存的文件数据仅是此数据的引用,因此要确保此数据一直存在 this->rawData = data; } qint64 DDciFilePrivate::writeMetaDataForNode(QIODevice *device, DDciFilePrivate::Node *node, qint64 dataSize) const { qint64 size = 0; device->putChar(static_cast(node->type)); size += FILE_TYPE_SIZE; const QByteArray rawName = node->name.toUtf8().left(FILE_NAME_SIZE - 1); size += device->write(rawName); // 填充未使用的部分 size += device->write(QByteArray(FILE_NAME_SIZE - rawName.size(), '\0')); char int64[FILE_DATA_SIZE]; qToLittleEndian(dataSize, int64); size += device->write(int64, FILE_DATA_SIZE); Q_ASSERT(size == FILE_META_SIZE); return size; } qint64 DDciFilePrivate::writeDataForNode(QIODevice *device, DDciFilePrivate::Node *node) const { if (node->type == FILE_TYPE_FILE || node->type == FILE_TYPE_SYMLINK) { return device->write(node->data); } else if (node->type == FILE_TYPE_DIR) { qint64 dataSize = 0; for (Node *child : node->children) { dataSize += writeNode(device, child); } return dataSize; } return 0; } qint64 DDciFilePrivate::writeNode(QIODevice *device, DDciFilePrivate::Node *node) const { const qint64 metaDataPos = device->pos(); device->seek(metaDataPos + FILE_META_SIZE); const qint64 dataSize = writeDataForNode(device, node); device->seek(metaDataPos); const qint64 metaDataSize = writeMetaDataForNode(device, node, dataSize); device->seek(device->pos() + dataSize); return metaDataSize + dataSize; } DDciFilePrivate::Node *DDciFilePrivate::mkNode(const QString &filePath) { qCDebug(logDF, "Request create a node"); if (pathToNode.contains(filePath)) { setErrorString(QString("The \"%1\" is existed").arg(filePath)); return nullptr; } const QFileInfo info(filePath); qCDebug(logDF, "The parent directory is \"%s\"", qPrintable(info.path())); if (Node *parentNode = pathToNode.value(info.path())) { if (parentNode->type != FILE_TYPE_DIR) { setErrorString(QString("The \"%1\" is not a directory").arg(info.path())); return nullptr; } // 检查文件名长度,避免溢出 if (info.fileName().toUtf8().size() > FILE_NAME_SIZE - 1) { setErrorString(QString("The file name size must less then %1 bytes").arg(FILE_NAME_SIZE)); return nullptr; } Node *newNode = new Node; newNode->name = info.fileName(); newNode->parent = parentNode; const int index = getOrderedIndexOfNodeName(parentNode->children, newNode->name); parentNode->children.insert(index, newNode); pathToNode[newNode->path()] = newNode; return newNode; } else { setErrorString("The parent directory is not exists"); return nullptr; } } void DDciFilePrivate::removeNode(DDciFilePrivate::Node *node) { Q_ASSERT(node != root.data()); node->parent->children.removeOne(node); auto removedNode = pathToNode.take(node->path()); Q_ASSERT(removedNode == node); for (Node *child : node->children) { Q_ASSERT(child->parent == node); auto removedNode = pathToNode.take(child->path()); Q_ASSERT(removedNode == child); } delete node; } void DDciFilePrivate::copyNode(const DDciFilePrivate::Node *from, DDciFilePrivate::Node *to) { QList> copyPendingList; copyPendingList << qMakePair(from, to); for (int i = 0; i < copyPendingList.size(); ++i) { auto f = copyPendingList.at(i).first; auto t = copyPendingList.at(i).second; t->type = f->type; t->data = f->data; for (const auto child : f->children) { if (child == to) continue; Node *newChild = new Node; newChild->parent = t; newChild->name = child->name; pathToNode[newChild->path()] = newChild; const int index = getOrderedIndexOfNodeName(t->children, newChild->name); t->children.insert(index, newChild); copyPendingList << qMakePair(child, newChild); } } } bool DDciFilePrivate::loadDirectory(DDciFilePrivate::Node *directory, const QByteArray &data, qint64 &offset, qint64 end, QHash &pathToNode) { // load files while (offset < end) { Node *node = new Node; node->parent = directory; node->type = data.at(offset); offset += FILE_TYPE_SIZE; // 计算文件名的长度 const int nameLength = data.indexOf('\0', offset) - offset; if (nameLength <= 0 || nameLength >= FILE_NAME_SIZE) { setErrorString(QString("Invalid file name, the data offset: %1").arg(offset)); delete node; return false; } node->name = QString::fromUtf8(data.constData() + offset, nameLength); offset += FILE_NAME_SIZE; const qint64 dataSize = qFromLittleEndian(data.constData() + offset); offset += FILE_DATA_SIZE; // 无失败时调用 break do { if (node->type == FILE_TYPE_DIR) { if (loadDirectory(node, data, offset, offset + dataSize - 1, pathToNode)) { break; } } else if (node->type == FILE_TYPE_FILE || node->type == FILE_TYPE_SYMLINK) { // 跳过文件内容 node->data = QByteArray::fromRawData(data.constData() + offset, dataSize); if (node->data.size() == dataSize) { offset += dataSize; break; } else { setErrorString(QString("Invalid data size of \"%1\" file").arg(node->path())); } } else { setErrorString(QString("Invalid file type: %1").arg(node->type)); } delete node; return false; } while (false); directory->children << node; pathToNode[node->path()] = node; } return true; } int DDciFilePrivate::getOrderedIndexOfNodeName(const decltype(Node::children) &list, const QString &name) { QCollator collator(QLocale::English); collator.setNumericMode(true); for (int i = 0; i < list.count(); ++i) { const Node *node = list.at(i); if (collator.compare(name, node->name) < 0) return i; } return list.count(); } void DDciFile::registerFileEngine() { // 在 QAbstractFileEngineHandler 的构造函数中会注册自己,后续 // 在使用 QFile 时会调用 DDciFileEngineHandler::create static DDciFileEngineHandler globalHandler; Q_UNUSED(globalHandler); } #ifndef DTK_NO_PROJECT DDciFile::DDciFile() : DObject(*new DDciFilePrivate(this)) { d_func()->load(QByteArrayLiteral("DCI\0\1\0\0\0")); } DDciFile::DDciFile(const QString &fileName) : DObject(*new DDciFilePrivate(this)) { d_func()->load(fileName); } DDciFile::DDciFile(const QByteArray &data) : DObject(*new DDciFilePrivate(this)) { d_func()->load(data); } #else DDciFile::DDciFile() : d(new DDciFilePrivate(this)) { d->load(QByteArrayLiteral("DCI\0\1\0\0\0")); } DDciFile::DDciFile(const QString &fileName) : d(new DDciFilePrivate(this)) { d->load(fileName); } DDciFile::DDciFile(const QByteArray &data) : d(new DDciFilePrivate(this)) { d->load(data); } #endif bool DDciFile::isValid() const { D_DC(DDciFile); return !!(d->root); } QString DDciFile::lastErrorString() const { D_DC(DDciFile); return d->errorMessage; } bool DDciFile::writeToFile(const QString &fileName) const { QSaveFile sf(fileName); do { if (!sf.open(QIODevice::WriteOnly)) { break; } if (!writeToDevice(&sf)) return false; if (!sf.commit()) break; return true; } while (false); qCDebug(logDF, "Failed on write to file \"%s\", error message is: \"%s\"", qPrintable(fileName), qPrintable(sf.errorString())); return false; } bool DDciFile::writeToDevice(QIODevice *device) const { Q_ASSERT(isValid()); D_DC(DDciFile); // magic device->write(QByteArrayLiteral("DCI\0")); // version device->putChar(static_cast(d->version)); char fileCountData[sizeof(int)]; qToLittleEndian(d->root->children.count(), fileCountData); // file count device->write(fileCountData, FILE_COUNT_SIZE); d->writeDataForNode(device, d->root.data()); return device->size() >= metadataSizeV1() + (d->pathToNode.count() - 1) * FILE_META_SIZE; } QByteArray DDciFile::toData() const { if (!isValid()) return QByteArray(); D_DC(DDciFile); qint64 allFilesContentSize = 0; for (auto node : d->pathToNode) { if (node->type == FILE_TYPE_FILE || node->type == FILE_TYPE_SYMLINK) allFilesContentSize += node->data.size(); } QByteArray data; // -1 是排除根目录 data.resize(metadataSizeV1() + (d->pathToNode.count() - 1) * FILE_META_SIZE + allFilesContentSize); QBuffer buffer(&data); if (!buffer.open(QIODevice::WriteOnly) || !writeToDevice(&buffer)) return QByteArray(); return data; } constexpr int DDciFile::metadataSizeV1() { return MAGIC_SIZE + VERSION_SIZE + FILE_COUNT_SIZE; } QStringList DDciFile::list(const QString &dir, bool onlyFileName) const { if (!isValid()) return {}; D_DC(DDciFile); auto dirNode = d->pathToNode.value(dir); if (!dirNode) { qCDebug(logDF, "The \"%s\" is not exists", qPrintable(dir)); return {}; } if (dirNode->type != FILE_TYPE_DIR) { qCWarning(logDF, "The \"%s\" is not a directory", qPrintable(dir)); return {}; } QStringList children; for (auto child : dirNode->children) { children << (onlyFileName ? child->name : QDir(dir).filePath(child->name)); } return children; } int DDciFile::childrenCount(const QString &dir) const { if (!isValid()) return 0; D_DC(DDciFile); auto dirNode = d->pathToNode.value(dir); if (!dirNode) { return 0; } return dirNode->children.count(); } bool DDciFile::exists(const QString &filePath) const { if (!isValid()) return false; D_DC(DDciFile); return d->pathToNode.contains(filePath); } DDciFile::FileType DDciFile::type(const QString &filePath) const { if (!isValid()) return UnknowFile; D_DC(DDciFile); auto node = d->pathToNode.value(filePath); if (!node) { qCDebug(logDF, "The \"%s\" is not exists", qPrintable(filePath)); return DDciFile::UnknowFile; } return static_cast(node->type); } QByteArray DDciFile::dataRef(const QString &filePath) const { if (!isValid()) return QByteArray(); D_DC(DDciFile); auto node = d->pathToNode.value(filePath); if (!node) { qCDebug(logDF, "The \"%s\" is not exists", qPrintable(filePath)); return QByteArray(); } if (node->type == FILE_TYPE_SYMLINK) { return dataRef(node->linkPath()); } return node->data; } QString DDciFile::name(const QString &filePath) const { if (!isValid()) return QString(); D_DC(DDciFile); if (auto node = d->pathToNode.value(filePath)) { return node->name; } return QString(); } QString DDciFile::symlinkTarget(const QString &filePath, bool originData) const { if (!isValid()) return QString(); D_DC(DDciFile); if (auto node = d->pathToNode.value(filePath)) { if (node->type != FILE_TYPE_SYMLINK) return QString(); if (originData) { return QString::fromUtf8(node->data); } const QString &linkPath = node->linkPath(); const auto targetNode = d->pathToNode.value(linkPath); // 链接的目标只能是“不存在的路径”、“文件”、“链接”,不可是目录 if (!targetNode || targetNode->type == FILE_TYPE_FILE || targetNode->type == FILE_TYPE_SYMLINK) return linkPath; } return QString(); } bool DDciFile::mkdir(const QString &filePath) { Q_ASSERT(isValid()); D_D(DDciFile); qCDebug(logDF, "Request create the \"%s\" directory", qPrintable(filePath)); auto node = d->mkNode(filePath); if (!node) return false; node->type = FILE_TYPE_DIR; return true; } bool DDciFile::writeFile(const QString &filePath, const QByteArray &data, bool override) { Q_ASSERT(isValid()); D_D(DDciFile); qCDebug(logDF, "Request create the \"%s\" file", qPrintable(filePath)); // 先删除旧的数据 if (auto node = d->pathToNode.value(filePath)) { if (override) { if (node->type == FILE_TYPE_SYMLINK) { const QString &linkPath = node->linkPath(); qCDebug(logDF(), "Follow the symlink to \"%s\"", qPrintable(linkPath)); if (!d->pathToNode.contains(linkPath)) { qCDebug(logDF(), "Can't write to a symlink target file if it is not existed"); return false; } return writeFile(linkPath, data, override); } qCDebug(logDF, "Try override the file"); if (node->type != FILE_TYPE_FILE) { qCWarning(logDF, "The \"%s\" is existed and it is not a file", qPrintable(filePath)); return false; } node->data = data; return true; } else { d->setErrorString("No the \"override\" flag and the file is existed, can't write"); return false; } } auto node = d->mkNode(filePath); if (!node) return false; node->type = FILE_TYPE_FILE; node->data = data; return true; } bool DDciFile::remove(const QString &filePath) { Q_ASSERT(isValid()); D_D(DDciFile); if (auto node = d->pathToNode.value(filePath)) { if (node == d->root.data()) { for (auto child : d->root->children) d->removeNode(child); d->root->children.clear(); } else { d->removeNode(node); } return true; } else { d->setErrorString("The file is not exists"); return false; } } bool DDciFile::rename(const QString &filePath, const QString &newFilePath, bool override) { Q_ASSERT(isValid()); D_D(DDciFile); qCDebug(logDF, "Rename from \"%s\" to \"%s\"", qPrintable(filePath), qPrintable(newFilePath)); if (filePath == newFilePath) return false; if (newFilePath.toUtf8().size() >= FILE_META_SIZE) { d->setErrorString(QString("The new name size must less then %1 bytes").arg(FILE_NAME_SIZE)); return false; } if (!override && d->pathToNode.contains(newFilePath)) { d->setErrorString("The target file is existed"); return false; } auto overrideNode = override ? d->pathToNode.take(newFilePath) : nullptr; if (auto node = d->pathToNode.take(filePath)) { QFileInfo info(newFilePath); if (auto parent = d->pathToNode.value(info.absolutePath())) { node->name = info.fileName(); // 从旧节点删除添加到新的节点 if (node->parent != parent) { bool ok = node->parent->children.removeOne(node); Q_ASSERT(ok); const int index = d->getOrderedIndexOfNodeName(parent->children, node->name); parent->children.insert(index, node); node->parent = parent; } d->pathToNode[info.absoluteFilePath()] = node; Q_ASSERT(node->path() == info.absoluteFilePath()); // 删除被覆盖的节点 if (overrideNode) { Q_ASSERT(overrideNode->parent == parent); overrideNode->parent->children.removeOne(overrideNode); delete overrideNode; } return true; } else { d->setErrorString(QString("The \"%1\" directory is not exists").arg(info.absolutePath())); return false; } } else { d->setErrorString("The file is not exists"); return false; } } bool DDciFile::copy(const QString &from, const QString &to) { Q_ASSERT(isValid()); D_D(DDciFile); const auto fromNode = d->pathToNode.value(from); if (!fromNode) { d->setErrorString(QString("The \"%1\" is not exists").arg(from)); return false; } auto toNode = d->mkNode(to); if (!toNode) { return false; } d->copyNode(fromNode, toNode); return true; } bool DDciFile::link(const QString &source, const QString &to) { Q_ASSERT(isValid()); D_D(DDciFile); if (source == to || source.isEmpty()) return false; auto toNode = d->mkNode(to); if (!toNode) return false; toNode->type = FILE_TYPE_SYMLINK; toNode->data = source.toUtf8(); return true; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dci/private/000077500000000000000000000000001476226660600162605ustar00rootroot00000000000000dtkcore-5.7.12/src/dci/private/ddcifileengine.cpp000066400000000000000000000450211476226660600217170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include //Avoid changing the access control of the standard library #endif #define private public #define protected public #include #undef private #undef protected #include "ddcifileengine_p.h" #include "dci/ddcifile.h" #include #include DCORE_BEGIN_NAMESPACE #ifdef QT_DEBUG Q_LOGGING_CATEGORY(logFE, "dtk.dci.fileengine") #else Q_LOGGING_CATEGORY(logFE, "dtk.dci.fileengine", QtInfoMsg) #endif #define DCI_FILE_SCHEME "dci:" #define DCI_FILE_SUFFIX ".dci" #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) std::unique_ptr DDciFileEngineHandler::create(const QString &fileName) const #else QAbstractFileEngine *DDciFileEngineHandler::create(const QString &fileName) const #endif { if (!fileName.startsWith(QStringLiteral(DCI_FILE_SCHEME))) return nullptr; #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) std::unique_ptr engine(new DDciFileEngine(fileName)); #else DDciFileEngine *engine = new DDciFileEngine(fileName); #endif if (!engine->isValid()) { #if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) delete engine; #endif return nullptr; } return engine; } // 共享同个线程内的同个 DDciFile static thread_local QHash> sharedDciFile; static void doDeleteSharedDciFile(const QString &path, DDciFile *file) { int count = sharedDciFile.remove(path); Q_ASSERT(count > 0); delete file; } static DDciFileShared getDciFile(const QString &dciFilePath, bool usePath = true) { if (auto shared = sharedDciFile.value(dciFilePath)) { return shared.toStrongRef(); } DDciFileShared shared(usePath ? new DDciFile(dciFilePath) : new DDciFile(), std::bind(doDeleteSharedDciFile, dciFilePath, std::placeholders::_1)); sharedDciFile[dciFilePath] = shared.toWeakRef(); return shared; } DDciFileEngineIterator::DDciFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters) #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) : QAbstractFileEngineIterator(nullptr, filters, nameFilters) #else : QAbstractFileEngineIterator(filters, nameFilters) #endif { } #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) DDciFileEngineIterator::DDciFileEngineIterator(QDirListing::IteratorFlags filters, const QStringList &nameFilters) : QAbstractFileEngineIterator(nullptr, filters, nameFilters) { } #endif #if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) QString DDciFileEngineIterator::next() { current = nextValid; return DDciFileEngineIterator::currentFileName(); } bool DDciFileEngineIterator::hasNext() const #else bool DDciFileEngineIterator::advance() #endif { if (!file) { const auto paths = DDciFileEngine::resolvePath(path()); if (paths.first.isEmpty() || paths.second.isEmpty()) return false; file = getDciFile(paths.first); list = file->list(paths.second); } for (int i = current + 1; i < list.count(); ++i) { // 先检查文件类型 const auto filters = this->filters(); const auto fileType = file->type(list.at(i)); if (fileType == DDciFile::Directory) { if (!filters.testFlag(QDir::Files)) continue; } else if (fileType == DDciFile::File) { if (!filters.testFlag(QDir::Files)) continue; } else if (fileType == DDciFile::Symlink) { if (filters.testFlag(QDir::NoSymLinks)) continue; } else { // DDciFile::UnknowFile continue; } // 按名称进行过滤 if (!nameFilters().isEmpty() && !QDir::match(nameFilters(), list.at(i))) continue; nextValid = i; #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) current = nextValid; #endif return true; } return false; } QString DDciFileEngineIterator::currentFileName() const { return file->name(list.at(current)); } DDciFileEngine::DDciFileEngine(const QString &fullPath) { setFileName(fullPath); } DDciFileEngine::~DDciFileEngine() { close(); } bool DDciFileEngine::isValid() const { return file && file->isValid(); } #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool DDciFileEngine::open(QIODevice::OpenMode openMode, std::optional permissions) #else bool DDciFileEngine::open(QIODevice::OpenMode openMode) #endif { if (fileBuffer) { setError(QFile::OpenError, "The file is opened"); return false; } if (!file->isValid()) { setError(QFile::OpenError, "The DCI file is invalid"); return false; } if (file->type(subfilePath) == DDciFile::Directory) { setError(QFile::OpenError, "Can't open a directory"); return false; } if (file->type(subfilePath) == DDciFile::Symlink) { if (!file->exists(file->symlinkTarget(subfilePath))) { setError(QFile::OpenError, "The symlink target is not existed"); return false; } } if (openMode & QIODevice::Text) { setError(QFile::OpenError, "Not supported open mode"); return false; } if (openMode & QIODevice::NewOnly) { if (file->exists(subfilePath)) { setError(QFile::OpenError, "The file is existed"); return false; } } if ((openMode & QIODevice::ExistingOnly) || !(openMode & QIODevice::WriteOnly)) { if (!file->exists(subfilePath)) { setError(QFile::OpenError, "The file is not exists"); return false; } } // 此时当文件不存在时应当创建它 if (openMode & QIODevice::WriteOnly) { realDciFile.setFileName(dciFilePath); #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) auto success = permissions ? realDciFile.open(openMode, permissions.value()) : realDciFile.open(openMode); if (!success) return false; #else if (!realDciFile.open(openMode)) { return false; } #endif // 不存在时尝试新建 if (!file->exists(subfilePath) && !file->writeFile(subfilePath, QByteArray())) { return false; } } // 加载数据 fileData = file->dataRef(subfilePath); fileBuffer = new QBuffer(&fileData); bool ok = fileBuffer->open(openMode); Q_ASSERT(ok); if (Q_UNLIKELY(!ok)) { delete fileBuffer; fileBuffer = nullptr; return false; } return true; } bool DDciFileEngine::close() { if (!fileBuffer) { return false; } fileBuffer->close(); delete fileBuffer; fileBuffer = nullptr; bool ok = flush(); realDciFile.close(); return ok; } bool DDciFileEngine::flushToFile(QFile *target, bool writeFile) const { if (target->isWritable()) { if (writeFile && !file->writeFile(subfilePath, fileData, true)) return false; if (!target->resize(0)) return false; const QByteArray &data = file->toData(); if (target->write(data) != data.size()) return false; return true; } return false; } bool DDciFileEngine::flush() { if (!flushToFile(&realDciFile, true)) return false; return realDciFile.flush(); } bool DDciFileEngine::syncToDisk() { if (!flush()) return false; return realDciFile.d_func()->engine()->syncToDisk(); } qint64 DDciFileEngine::size() const { if (fileBuffer) { return fileData.size(); } return file->dataRef(subfilePath).size(); } qint64 DDciFileEngine::pos() const { return fileBuffer->size(); } bool DDciFileEngine::seek(qint64 pos) { return fileBuffer->seek(pos); } bool DDciFileEngine::isSequential() const { return false; } bool DDciFileEngine::remove() { return file->isValid() && file->remove(subfilePath) && forceSave(); } bool DDciFileEngine::copy(const QString &newName) { if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 const auto paths = resolvePath(newName, dciFilePath); if (paths.second.isEmpty()) return false; return file->copy(subfilePath, paths.second) && forceSave(); } bool DDciFileEngine::rename(const QString &newName) { if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 const auto paths = resolvePath(newName, dciFilePath); if (paths.second.isEmpty()) return false; return file->rename(subfilePath, paths.second, false) && forceSave(); } bool DDciFileEngine::renameOverwrite(const QString &newName) { if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 const auto paths = resolvePath(newName, dciFilePath); if (paths.second.isEmpty()) return false; return file->rename(subfilePath, paths.second, true) && forceSave(); } bool DDciFileEngine::link(const QString &newName) { if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 const auto paths = resolvePath(newName, dciFilePath); const QString &linkPath = paths.second.isEmpty() ? newName : paths.second; return file->link(subfilePath, linkPath) && forceSave(); } #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool DDciFileEngine::mkdir(const QString &dirName, bool createParentDirectories, std::optional permissions) const { Q_UNUSED(permissions) #else bool DDciFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const { #endif if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 const auto paths = resolvePath(dirName, dciFilePath); if (paths.second.isEmpty()) return false; if (!createParentDirectories) return file->mkdir(paths.second) && forceSave(); const QStringList dirItems = paths.second.split('/'); QString currentPath; for (const QString &newDir : dirItems) { if (newDir.isEmpty()) continue; currentPath += ("/" + newDir); if (file->exists(currentPath)) { continue; } // 创建此路径 if (!file->mkdir(currentPath)) return false; } return forceSave(); } bool DDciFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const { if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 const auto paths = resolvePath(dirName, dciFilePath); if (paths.second.isEmpty()) return false; if (!file->remove(paths.second)) return false; if (!recurseParentDirectories) return forceSave(); // 查找空的父目录 QDir dir(paths.second); while (dir.cdUp()) { // 不删除根 if (dir.isRoot()) break; if (file->childrenCount(dir.absolutePath()) > 0) continue; if (!file->remove(dir.absolutePath())) return false; } return forceSave(); } bool DDciFileEngine::setSize(qint64 size) { if (!fileBuffer) { fileData = file->dataRef(subfilePath); } // 确保新数据填充为 0 if (size > fileData.size()) { fileData.append(size - fileData.size(), '\0'); } else { fileData.resize(size); } return fileBuffer ? true : forceSave(true); } bool DDciFileEngine::caseSensitive() const { return true; } bool DDciFileEngine::isRelativePath() const { return !subfilePath.startsWith('/'); } QByteArray DDciFileEngine::id() const { return fileName().toUtf8(); } uint DDciFileEngine::ownerId(QAbstractFileEngine::FileOwner owner) const { QFileInfo info(dciFilePath); return owner == OwnerUser ? info.ownerId() : info.groupId(); } QString DDciFileEngine::owner(QAbstractFileEngine::FileOwner owner) const { QFileInfo info(dciFilePath); return owner == OwnerUser ? info.owner() : info.group(); } QAbstractFileEngine::FileFlags DDciFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const { auto flags = QAbstractFileEngine::FileFlags(); if (!file->isValid()) return flags; if (type & TypesMask) { const auto fileType = file->type(subfilePath); if (fileType == DDciFile::Directory) { flags |= DirectoryType; } else if (fileType == DDciFile::File) { flags |= FileType; } else if (fileType == DDciFile::Symlink) { flags |= LinkType; } } if ((type & FlagsMask)) { if (file->exists(subfilePath)) flags |= ExistsFlag; if (subfilePath == QLatin1Char('/')) flags |= RootFlag; } if ((type & PermsMask) && file->exists(subfilePath)) { flags |= static_cast(static_cast(QFileInfo(dciFilePath).permissions())); } return flags; } QString DDciFileEngine::fileName(QAbstractFileEngine::FileName file) const { switch (file) { case AbsoluteName: case CanonicalName: case DefaultName: return QDir::cleanPath(DCI_FILE_SCHEME + dciFilePath + subfilePath); case AbsolutePathName: return QDir::cleanPath(DCI_FILE_SCHEME + dciFilePath); case BaseName: return QFileInfo(subfilePath).baseName(); #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) case AbsoluteLinkTarget: #else case LinkName: #endif return this->file->type(subfilePath) == DDciFile::Symlink ? this->file->symlinkTarget(subfilePath) : QString(); default: break; } return QString(); } void DDciFileEngine::setFileName(const QString &fullPath) { // 销毁旧的内容 close(); file.reset(nullptr); dciFilePath.clear(); subfilePath.clear(); const auto paths = resolvePath(fullPath, QString(), false); if (paths.first.isEmpty() || paths.second.isEmpty()) return; dciFilePath = paths.first; subfilePath = paths.second; file = getDciFile(dciFilePath, QFile::exists(dciFilePath)); } #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 1) QDateTime DDciFileEngine::fileTime(QFile::FileTime time) const { return QFileInfo(dciFilePath).fileTime(time); } #else QDateTime DDciFileEngine::fileTime(QAbstractFileEngine::FileTime time) const { return QFileInfo(dciFilePath).fileTime(static_cast(time)); } #endif #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) QAbstractFileEngine::IteratorUniquePtr DDciFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) #elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) QAbstractFileEngine::IteratorUniquePtr DDciFileEngine::beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) #else DDciFileEngine::Iterator *DDciFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) #endif { #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) Q_UNUSED(path); return QAbstractFileEngine::IteratorUniquePtr(new DDciFileEngineIterator(filters, filterNames)); #else return new DDciFileEngineIterator(filters, filterNames); #endif } #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) QAbstractFileEngine::IteratorUniquePtr DDciFileEngine::endEntryList() #else DDciFileEngine::Iterator *DDciFileEngine::endEntryList() #endif { return nullptr; } qint64 DDciFileEngine::read(char *data, qint64 maxlen) { return fileBuffer->read(data, maxlen); } qint64 DDciFileEngine::write(const char *data, qint64 len) { return fileBuffer->write(data, len); } bool DDciFileEngine::extension(QAbstractFileEngine::Extension extension, const QAbstractFileEngine::ExtensionOption *option, QAbstractFileEngine::ExtensionReturn *output) { Q_UNUSED(option) Q_UNUSED(output) return extension == AtEndExtension && fileBuffer->atEnd(); } bool DDciFileEngine::supportsExtension(QAbstractFileEngine::Extension extension) const { return extension == AtEndExtension; } bool DDciFileEngine::cloneTo(QAbstractFileEngine *target) { const QByteArray &data = file->dataRef(subfilePath); return target->write(data.constData(), data.size()) == data.size(); } bool DDciFileEngine::forceSave(bool writeFile) const { QFile file(dciFilePath); if (!file.open(QIODevice::WriteOnly)) { return false; } return flushToFile(&file, writeFile); } QPair DDciFileEngine::resolvePath(const QString &fullPath, const QString &realFilePath, bool needRealFileExists) { if (!fullPath.startsWith(QStringLiteral(DCI_FILE_SCHEME) + realFilePath)) return {}; qCDebug(logFE(), "Resolve the path: \"%s\"", qPrintable(fullPath)); // 此路径来源于调用方,将其格式化为标准格式,尾部添加 "/" 以确保下文中得到的 // subfilePath 绝对不为空 QString formatFullPath = QDir::cleanPath(fullPath) + "/"; QString dciFilePath = realFilePath, subfilePath; const int schemeLength = qstrlen(DCI_FILE_SCHEME); const int suffixLength = qstrlen(DCI_FILE_SUFFIX); if (dciFilePath.isEmpty()) { // 尾部加 "/" 是确保 ".dci" 为一个文件的结尾 int dciSuffixIndex = formatFullPath.indexOf(DCI_FILE_SUFFIX "/", schemeLength); while (dciSuffixIndex > 0) { dciSuffixIndex += suffixLength; dciFilePath = formatFullPath.mid(schemeLength, dciSuffixIndex - schemeLength); // 查找一个有效的后缀名是 ".dci" 的文件 if (needRealFileExists) { if (QFileInfo(dciFilePath).isFile()) break; } else { QFileInfo info(dciFilePath); // 不存在的文件允许被新建 if (!info.exists() && !info.isSymLink()) break; } dciSuffixIndex = dciFilePath.indexOf(DCI_FILE_SUFFIX, dciSuffixIndex + 1); } } else { qCDebug(logFE(), "The base file path of user is: \"%s\"", qPrintable(realFilePath)); } // 未找到有效的 dci 文件 if (dciFilePath.isEmpty()) return {}; subfilePath = QDir::cleanPath(formatFullPath.mid(schemeLength + dciFilePath.length())); qCDebug(logFE(), "The DCI file path is: \"%s\", the subfile path is: \"%s\"", qPrintable(dciFilePath), qPrintable(subfilePath)); Q_ASSERT(!subfilePath.isEmpty()); return qMakePair(dciFilePath, subfilePath); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dci/private/ddcifileengine_p.h000066400000000000000000000121411476226660600217000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #ifndef DTK_NO_PROJECT #include #else #define DCORE_BEGIN_NAMESPACE #define DCORE_END_NAMESPACE #endif #include #include #include QT_BEGIN_NAMESPACE class QBuffer; QT_END_NAMESPACE DCORE_BEGIN_NAMESPACE class DDciFileEngineHandler : public QAbstractFileEngineHandler { public: #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) std::unique_ptr create(const QString &fileName) const override; #else QAbstractFileEngine *create(const QString &fileName) const override; #endif }; class DDciFile; using DDciFileShared = QSharedPointer; class DDciFileEngineIterator : public QAbstractFileEngineIterator { friend class DDciFileEngine; public: DDciFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters); #if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) QString next() override; bool hasNext() const override; #else DDciFileEngineIterator(QDirListing::IteratorFlags filters, const QStringList &nameFilters); bool advance() override; #endif QString currentFileName() const override; private: mutable DDciFileShared file; mutable QStringList list; mutable int nextValid = -1; int current = -1; }; class DDciFileEngine : public QAbstractFileEngine { friend class DDciFileEngineIterator; public: explicit DDciFileEngine(const QString &fullPath); ~DDciFileEngine(); bool isValid() const; #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool open(QIODevice::OpenMode openMode, std::optional permissions = std::nullopt) override; #else bool open(QIODevice::OpenMode openMode) override; #endif bool close() override; bool flushToFile(QFile *target, bool writeFile) const; bool flush() override; bool syncToDisk() override; qint64 size() const override; qint64 pos() const override; bool seek(qint64 pos) override; bool isSequential() const override; bool remove() override; bool copy(const QString &newName) override; bool rename(const QString &newName) override; bool renameOverwrite(const QString &newName) override; bool link(const QString &newName) override; #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool mkdir(const QString &dirName, bool createParentDirectories, std::optional permissions = std::nullopt) const override; #else bool mkdir(const QString &dirName, bool createParentDirectories) const override; #endif bool rmdir(const QString &dirName, bool recurseParentDirectories) const override; bool setSize(qint64 size) override; bool caseSensitive() const override; bool isRelativePath() const override; QByteArray id() const override; uint ownerId(FileOwner owner) const override; QString owner(FileOwner owner) const override; FileFlags fileFlags(FileFlags type = FileInfoAll) const override; QString fileName(FileName file = DefaultName) const override; void setFileName(const QString &fullPath) override; #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 1) QDateTime fileTime(QFile::FileTime time) const override; #else QDateTime fileTime(FileTime time) const override; #endif typedef DDciFileEngineIterator Iterator; #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override; IteratorUniquePtr endEntryList() override; #elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override; IteratorUniquePtr endEntryList() override; #else Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override; Iterator *endEntryList() override; #endif qint64 read(char *data, qint64 maxlen) override; qint64 write(const char *data, qint64 len) override; bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) override; bool supportsExtension(Extension extension) const override; bool cloneTo(QAbstractFileEngine *target) override; private: bool forceSave(bool writeFile = false) const; /* * fullPath 格式:"dci:" + "真实文件路径" + "DCI 内部文件的路径" * 例如:"dci:/home/user/test.dci/subfile.png" * 其中 "/home/user/test.dci" 为真实文件路径,"/subfile.png" * 是 DCI 文件的内部路径。 * 函数返回的第一个数据是"真实文件路径"。 */ static QPair resolvePath(const QString &fullPath, const QString &realFilePath = QString(), bool needRealFileExists = true); DDciFileShared file; QString dciFilePath; QFile realDciFile; QString subfilePath; QByteArray fileData; QBuffer *fileBuffer = nullptr; }; DCORE_END_NAMESPACE dtkcore-5.7.12/src/dconfig.cpp000066400000000000000000000560521476226660600161740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dconfig.h" #ifndef D_DISABLE_DCONFIG #include "dconfigfile.h" #ifndef D_DISABLE_DBUS_CONFIG #include "configmanager_interface.h" #include "manager_interface.h" #endif #else #include #endif #include "dobject_p.h" #include #include #include #include // https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/issues/3 DCORE_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(cfLog) static QString NoAppId; /*! @~english @class Dtk::Core::DConfigBackend \inmodule dtkcore @brief Configure the abstract interface of the backend. All configuration backends used by DConfig inherit this class, and users can inherit this class to implement their own configuration backends. */ /*! @~english @fn bool DConfigBackend::load(const QString &) = 0 @brief Initialize the backend \a appId Managed configuration information key value, the default is the application name. */ /*! @~english @fn bool DConfigBackend::isValid() const = 0 @sa DConfig::isValid(). */ /*! @~english @fn QStringList DConfigBackend::keyList() const = 0 @sa DConfig::keyList() */ /*! @~english @fn QVariant DConfigBackend::value(const QString &key, const QVariant &fallback = QVariant()) const = 0 @sa DConfig::value() */ /*! @~english @fn void DConfigBackend::setValue(const QString &key, const QVariant &value) = 0 @sa DConfig::setValue() */ /*! @~english @fn void DConfigBackend::reset(const QString &key) @sa DConfig::reset() */ /*! @~english @fn QString DConfigBackend::name() const = 0 @brief The unique identity of the backend configuration */ /*! @~english @fn bool DConfigBackend::isDefaultValue(const QString &key) const = 0 @sa DConfig::isDefaultValue() */ DConfigBackend::~DConfigBackend() { } static QString _globalAppId; class Q_DECL_HIDDEN DConfigPrivate : public DObjectPrivate { public: explicit DConfigPrivate(DConfig *qq, const QString &appId, const QString &name, const QString &subpath) : DObjectPrivate(qq) , appId(appId) , name(name) , subpath(subpath) { } virtual ~DConfigPrivate() override; inline bool invalid() const { const bool valid = backend && backend->isValid(); if (!valid) qCWarning(cfLog, "DConfig is invalid of appid=%s name=%s, subpath=%s", qPrintable(appId), qPrintable(name), qPrintable(subpath)); return !valid; } DConfigBackend *getOrCreateBackend(); DConfigBackend *createBackendByEnv(); QString appId; QString name; QString subpath; QScopedPointer backend; D_DECLARE_PUBLIC(DConfig) }; namespace { #ifndef D_DISABLE_DCONFIG class Q_DECL_HIDDEN FileBackend : public DConfigBackend { public: explicit FileBackend(DConfigPrivate *o) : owner(o) { } virtual ~FileBackend() override; virtual bool isValid() const override { return configFile && configFile->isValid(); } virtual bool load(const QString &/*appId*/) override { if (configFile) return true; configFile.reset(new DConfigFile(owner->appId,owner->name, owner->subpath)); configCache.reset(configFile->createUserCache(getuid())); const QString &prefix = localPrefix(); if (!configFile->load(prefix) || !configCache->load(prefix)) return false; // generic config doesn't need to fallback to generic configration. if (owner->appId == NoAppId) return true; QScopedPointer file(new DConfigFile(NoAppId, owner->name, owner->subpath)); const bool canFallbackToGeneric = !file->meta()->metaPath(prefix).isEmpty(); if (canFallbackToGeneric) { QScopedPointer cache(file->createUserCache(getuid())); if (file->load(prefix) && cache->load(prefix)) { genericConfigFile.reset(file.take()); genericConfigCache.reset(cache.take()); } } return true; } virtual QStringList keyList() const override { return configFile->meta()->keyList(); } virtual QVariant value(const QString &key, const QVariant &fallback) const override { const QVariant &vc = configFile->cacheValue(configCache.get(), key); if (vc.isValid()) return vc; // fallback to generic configuration, and use itself's configuration if generic isn't set. if (genericConfigFile) { const auto &tmp = genericConfigFile->cacheValue(genericConfigCache.get(), key); if (tmp.isValid()) return tmp; } const QVariant &v = configFile->value(key); if (v.isValid()) return v; // fallback to default value of generic configuration. const QVariant &vg = genericConfigFile->value(key); return vg.isValid() ? vg : fallback; } virtual bool isDefaultValue(const QString &key) const override { // Don't fallback to generic configuration const QVariant &vc = configFile->cacheValue(configCache.get(), key); return !vc.isValid(); } virtual void setValue(const QString &key, const QVariant &value) override { // setValue's callerAppid is itself instead of config's appId. if (configFile->setValue(key, value, DSGApplication::id(), configCache.get())) { Q_EMIT owner->q_func()->valueChanged(key); } } virtual void reset(const QString &key) override { setValue(key, QVariant()); } virtual QString name() const override { return QString("FileBackend"); } private: QString localPrefix() const { if (!envLocalPrefix.isEmpty()) { return QString::fromLocal8Bit(envLocalPrefix); } return QString(); } private: QScopedPointer configFile; QScopedPointer configCache; QScopedPointer genericConfigFile; QScopedPointer genericConfigCache; DConfigPrivate* owner; const QByteArray envLocalPrefix = qgetenv("DSG_DCONFIG_FILE_BACKEND_LOCAL_PREFIX"); }; FileBackend::~FileBackend() { const QString &prefix = localPrefix(); if (configCache) { configCache->save(prefix); configCache.reset(); } if (configFile) { configFile->save(prefix); configFile.reset(); } if (genericConfigCache) { genericConfigCache->save(prefix); genericConfigCache.reset(); } if (genericConfigFile) { genericConfigFile->save(prefix); genericConfigFile.reset(); } } #ifndef D_DISABLE_DBUS_CONFIG #define DSG_CONFIG "org.desktopspec.ConfigManager" #define DSG_CONFIG_MANAGER "org.desktopspec.ConfigManager" class Q_DECL_HIDDEN DBusBackend : public DConfigBackend { public: explicit DBusBackend(DConfigPrivate* o): owner(o) { } virtual ~DBusBackend() override; static bool isServiceRegistered() { return QDBusConnection::systemBus().interface()->isServiceRegistered(DSG_CONFIG); } static bool isServiceActivatable() { const QDBusReply activatableNames = QDBusConnection::systemBus().interface()-> callWithArgumentList(QDBus::AutoDetect, QLatin1String("ListActivatableNames"), QList()); // qInfo() << activatableNames.value() << activatableNames.value().contains(DSG_CONFIG); return activatableNames.value().contains(DSG_CONFIG); } virtual bool isValid() const override { return config && config->isValid(); } /*! @~english \internal Initialize the DBus connection, the call acquireManager dynamically obtains a configuration connection, The configuration file is then accessed through this configuration connection. */ virtual bool load(const QString &/*appId*/) override { if (config) return true; qCDebug(cfLog, "Try acquire config manager object form DBus"); DSGConfig dsg_config(DSG_CONFIG, "/", QDBusConnection::systemBus()); QDBusPendingReply dbus_reply = dsg_config.acquireManager(owner->appId, owner->name, owner->subpath); const QDBusObjectPath dbus_path = dbus_reply.value(); if (dbus_reply.isError() || dbus_path.path().isEmpty()) { qCWarning(cfLog, "Can't acquire config manager. error:\"%s\"", qPrintable(dbus_reply.error().message())); return false; } else { qCDebug(cfLog(), "dbus path=\"%s\"", qPrintable(dbus_path.path())); config.reset(new DSGConfigManager(DSG_CONFIG_MANAGER, dbus_path.path(), QDBusConnection::systemBus(), owner->q_func())); if (!config->isValid()) { qCWarning(cfLog(), "Can't acquire config path=\"%s\"", qPrintable(dbus_path.path())); config.reset(); return false; } else { QObject::connect(config.data(), &DSGConfigManager::valueChanged, owner->q_func(), &DConfig::valueChanged); } } return true; } virtual QStringList keyList() const override { return config->keyList(); } static QVariant decodeQDBusArgument(const QVariant &v) { if (v.canConvert()) { // we use QJsonValue to resolve all data type in DConfigInfo class, so it's type is equal QJsonValue::Type, // now we parse Map and Array type to QVariant explicitly. const QDBusArgument &complexType = v.value(); switch (complexType.currentType()) { case QDBusArgument::MapType: { QVariantMap list; complexType >> list; QVariantMap res; for (auto iter = list.begin(); iter != list.end(); iter++) { res[iter.key()] = decodeQDBusArgument(iter.value()); } return res; } case QDBusArgument::ArrayType: { QVariantList list; complexType >> list; QVariantList res; res.reserve(list.size()); for (const auto &item : qAsConst(list)) { res << decodeQDBusArgument(item); } return res; } default: qWarning("Can't parse the type, it maybe need user to do it, " "QDBusArgument::ElementType: %d.", complexType.currentType()); } } return v; } virtual QVariant value(const QString &key, const QVariant &fallback) const override { auto reply = config->value(key); reply.waitForFinished(); if (reply.isError()) { qWarning() << "value error key:" << key << ", error message:" << reply.error().message(); return fallback; } return decodeQDBusArgument(reply.value().variant()); } virtual bool isDefaultValue(const QString &key) const override { auto reply = config->isDefaultValue(key); reply.waitForFinished(); if (reply.isError()) { qWarning() << "Failed to call `isDefaultValue`, key:" << key << ", error message:" << reply.error().message(); return false; } return reply.value(); } virtual void setValue(const QString &key, const QVariant &value) override { auto reply = config->setValue(key, QDBusVariant(value)); reply.waitForFinished(); if (reply.isError()) qCWarning(cfLog) << "Failed to setValue for the key:" << key << ", error message:" << reply.error(); } virtual void reset(const QString &key) override { auto reply = config->reset(key); reply.waitForFinished(); if (reply.isError()) qCWarning(cfLog) << "Failed to reset for the key:" << key << ", error message:" << reply.error(); } virtual QString name() const override { return QString("DBusBackend"); } private: QScopedPointer config; DConfigPrivate* owner; }; DBusBackend::~DBusBackend() { if (config) { config->release(); } } #endif //D_DISABLE_DBUS_CONFIG #else class Q_DECL_HIDDEN QSettingBackend : public DConfigBackend { public: explicit QSettingBackend(DConfigPrivate* o): owner(o) { } virtual ~QSettingBackend() override; virtual bool isValid() const override { return settings; } virtual bool load(const QString &appid) override { Q_UNUSED(appid); if (settings) return true; settings = new QSettings(owner->name, QSettings::IniFormat, owner->q_func()); settings->beginGroup(owner->subpath); return true; } virtual QStringList keyList() const override { return settings->childKeys(); } virtual QVariant value(const QString &key, const QVariant &fallback) const override { return settings->value(key, fallback); } virtual void setValue(const QString &key, const QVariant &value) override { settings->setValue(key, value); } virtual QString name() const override { return QString("QSettingBackend"); } private: QSettings *settings = nullptr; DConfigPrivate* owner; }; QSettingBackend::~QSettingBackend() { } #endif //D_DISABLE_DCONFIG } DConfigPrivate::~DConfigPrivate() { backend.reset(); } /*! @~english \internal @brief Create a configuration backend The default configuration backend preferentially selects the D-Bus interface in the configuration center or the file configuration backend interface based on environment variables. If this environment variable is not configured, the configuration center service or file configuration backend interface will be selected according to whether the configuration center provides D-Bus services */ DConfigBackend *DConfigPrivate::getOrCreateBackend() { if (backend) { return backend.data(); } if (auto backendEnv = createBackendByEnv()) { backend.reset(backendEnv); return backend.data(); } #ifndef D_DISABLE_DCONFIG #ifndef D_DISABLE_DBUS_CONFIG if (DBusBackend::isServiceRegistered() || DBusBackend::isServiceActivatable()) { qCDebug(cfLog, "Fallback to DBus mode"); backend.reset(new DBusBackend(this)); } if (!backend) { qCDebug(cfLog, "Can't use DBus config service, fallback to DConfigFile mode"); backend.reset(new FileBackend(this)); } #else backend.reset(new FileBackend(this)); #endif //D_DISABLE_DBUS_CONFIG #else qCDebug(cfLog, "Fallback to QSettings mode"); backend.reset(new QSettingBackend(this)); #endif //D_DISABLE_DCONFIG return backend.data(); } /*! @~english \internal @brief Create a configuration backend Try to choose between configuring the D-Bus interface in the center or the file configuration backend interface based on the environment variables. */ DConfigBackend *DConfigPrivate::createBackendByEnv() { const QByteArray &envBackend = qgetenv("DSG_DCONFIG_BACKEND_TYPE"); if (!envBackend.isEmpty()) { if (envBackend == "DBusBackend") { #ifndef D_DISABLE_DCONFIG #ifndef D_DISABLE_DBUS_CONFIG if (DBusBackend::isServiceRegistered() || DBusBackend::isServiceActivatable()) { qCDebug(cfLog, "Fallback to DBus mode"); return new DBusBackend(this); } #endif //D_DISABLE_DBUS_CONFIG #endif //D_DISABLE_DCONFIG } else if (envBackend == "FileBackend") { #ifndef D_DISABLE_DCONFIG qCDebug(cfLog, "Fallback to DConfigFile mode"); return new FileBackend(this); #endif //D_DISABLE_DCONFIG } else { #ifndef D_DISABLE_DCONFIG #else qCDebug(cfLog, "Fallback to QSettings mode"); return new QSettingBackend(this); #endif //D_DISABLE_DCONFIG } } return nullptr; } /*! @~english @class Dtk::Core::DConfig \inmodule dtkcore @brief Configure the interface class provided by the policy This interface specification defines the relevant interfaces provided by the development library for reading and writing configuration files, If the application uses a development library that implements this specification, the application should use the interfaces provided by the development library first. */ /*! @~english * @brief Constructs the objects provided by the configuration policy * \a name Configuration File Name * \a subpath Subdirectory corresponding to the configuration file * \a parent Parent object */ DConfig::DConfig(const QString &name, const QString &subpath, QObject *parent) : DConfig(nullptr, name, subpath, parent) { } DConfig::DConfig(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) : DConfig(backend, _globalAppId.isEmpty() ? DSGApplication::id() : _globalAppId, name, subpath, parent) { } /*! @~english * @brief Constructs the object provided by the configuration policy, specifying the application Id to which the configuration belongs. * \a appId * \a name * \a subpath * \a parent * @return The constructed configuration policy object, which is released by the caller * @note \a appId is not empty. */ DConfig *DConfig::create(const QString &appId, const QString &name, const QString &subpath, QObject *parent) { Q_ASSERT(appId != NoAppId); return new DConfig(nullptr, appId, name, subpath, parent); } DConfig *DConfig::create(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) { Q_ASSERT(appId != NoAppId); return new DConfig(backend, appId, name, subpath, parent); } /*! * \brief Constructs the object, and which is application. * \param name * \param subpath * \param parent * \return Dconfig object, which is released by the caller * @note It's usually used for application independent, we should use DConfig::create if the configuration is a specific application. */ DConfig *DConfig::createGeneric(const QString &name, const QString &subpath, QObject *parent) { return new DConfig(nullptr, NoAppId, name, subpath, parent); } DConfig *DConfig::createGeneric(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) { return new DConfig(backend, NoAppId, name, subpath, parent); } /*! * \brief Explicitly specify application Id for config. * \param appId * @note It's should be called before QCoreApplication constructed. */ void DConfig::setAppId(const QString &appId) { if (!_globalAppId.isEmpty()) { qCWarning(cfLog, "`setAppId`should only be called once."); } _globalAppId = appId; qCDebug(cfLog, "Explicitly specify application Id as appId=%s for config.", qPrintable(appId)); } class DConfigThread : public QThread { public: DConfigThread() { setObjectName("DConfigGlobalThread"); start(); } ~DConfigThread() override { if (isRunning()) { quit(); wait(); } } }; Q_GLOBAL_STATIC(DConfigThread, _globalThread) QThread *DConfig::globalThread() { return _globalThread; } /*! @~english * @brief Use custom configuration policy backend to construct objects * \a backend The caller inherits the configuration policy backend of DConfigBackend * \a appId The application Id of the configuration file. If it is blank, it will be the application Id by default * \a name Configuration File Name * \a subpath Subdirectory corresponding to the configuration file * \a parent Parent object * @note The caller only constructs backend, which is released by DConfig. */ DConfig::DConfig(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) : QObject(parent) , DObject(*new DConfigPrivate(this, appId, name, subpath)) { D_D(DConfig); qCDebug(cfLog, "Load config of appid=%s name=%s, subpath=%s", qPrintable(d->appId), qPrintable(d->name), qPrintable(d->subpath)); if (backend) { d->backend.reset(backend); } if (auto backend = d->getOrCreateBackend()) { backend->load(d->appId); } } /*! @~english * @brief DConfig::backendName * @return Configure policy backend name * @note The caller can only access the DConfigBackend object with DConfig, so the DConfigBackend object is not returned. */ QString DConfig::backendName() const { D_DC(DConfig); if (d->invalid()) return QString(); return d->backend->name(); } /*! @~english * @brief Get all available configuration item names * @return Configuration item name collection */ QStringList DConfig::keyList() const { D_DC(DConfig); if (d->invalid()) return QStringList(); return d->backend->keyList(); } /*! @~english * @brief Check whether the backend is available * @return */ bool DConfig::isValid() const { D_DC(DConfig); return !d->invalid(); } /*! @~english * @brief Check whether the value is default according to the configuration item name * @param key Configuration Item Name * @return Return `true` if the value isn't been set, otherwise return `false` */ bool DConfig::isDefaultValue(const QString &key) const { D_DC(DConfig); if (d->invalid()) return false; return d->backend->isDefaultValue(key); } /*! @~english * @brief Get the corresponding value according to the configuration item name * @param key Configuration Item Name * @param fallback The default value provided after the configuration item value is not obtained * @return */ QVariant DConfig::value(const QString &key, const QVariant &fallback) const { D_DC(DConfig); if (d->invalid()) return fallback; return d->backend->value(key, fallback); } /*! @~english * @brief Set the value according to the configuration item name * @param key Configuration Item Name * @param value Values that need to be updated */ void DConfig::setValue(const QString &key, const QVariant &value) { D_D(DConfig); if (d->invalid()) return; d->backend->setValue(key, value); } /*! @~english * @brief Set the default value corresponding to its configuration item. This value is overridden by the override mechanism. It is not necessarily the value defined in the meta in this configuration file * @param key Configuration Item Name */ void DConfig::reset(const QString &key) { D_D(DConfig); if (d->invalid()) return; d->backend->reset(key); } /*! @~english * @brief Return configuration file name * @return */ QString DConfig::name() const { D_DC(DConfig); return d->name; } /*! @~english * @brief Return the subdirectory corresponding to the configuration file * @return */ QString DConfig::subpath() const { D_DC(DConfig); return d->subpath; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dconfigfile.cpp000066400000000000000000001345111476226660600170310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dconfigfile.h" #include "dobject_p.h" #include "filesystem/dstandardpaths.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/issues/3 DCORE_BEGIN_NAMESPACE #ifndef QT_DEBUG Q_LOGGING_CATEGORY(cfLog, "dtk.dsg.config" , QtInfoMsg); #else Q_LOGGING_CATEGORY(cfLog, "dtk.dsg.config"); #endif #define FILE_SUFFIX QLatin1String(".json") // subpath must be a subdirectory of the dir. inline static bool subpathIsValid(const QString &subpath, const QDir &dir) { if (subpath.isEmpty()) return true; const QDir subDir(dir.filePath(subpath.mid(1))); return subDir.absolutePath().startsWith(dir.absolutePath()); } // name must be a valid filename. inline static bool isValidFilename(const QString& filename) { static const QRegularExpression regex("^[\\w\\-\\.\\ ]+$"); QRegularExpressionMatch match = regex.match(filename); return match.hasMatch(); } // AppId don't contain ' ', but it can be empty. inline static bool isValidAppId(const QString& appId) { static const QRegularExpression regex("^[\\w\\-\\.]*$"); QRegularExpressionMatch match = regex.match(appId); return match.hasMatch(); } /*! @~english \internal @brief 按子目录查找机制查找配置文件 在 \a baseDir目录下,查找名称为 \a name的文件, 若存在 \a subpath,则从 \a subpath叶子目录逐级向上查找名称为 \a name的文件, 若不存在此文件,则返回无效路径. */ inline QString getFile(const QString &baseDir, const QString &subpath, const QString &name, bool canFallbackUp = true) { qCDebug(cfLog, "load json file from base dir:\"%s\", subpath = \"%s\", file name =\"%s\".", qPrintable(baseDir), qPrintable(subpath), qPrintable(name)); const QDir base_dir(baseDir); if (!subpathIsValid(subpath, base_dir)) { qCDebug(cfLog, "subpath is invalid in the base dir:\"%s\", subpath:\"%s\".", qPrintable(baseDir), qPrintable(subpath)); return QString(); } QDir target_dir = base_dir; if (!subpath.isEmpty()) target_dir.cd(subpath.mid(1)); do { qCDebug(cfLog, "load json file from: \"%s\"", qPrintable(target_dir.path())); if (QFile::exists(target_dir.filePath(name))) { return target_dir.filePath(name); } if (base_dir == target_dir) break; } while (canFallbackUp && target_dir.cdUp()); return QString(); } inline QFile *loadFile(const QString &baseDir, const QString &subpath, const QString &name, bool canFallbackUp = true) { QString path = getFile(baseDir, subpath, name, canFallbackUp); if (!path.isEmpty()) { return new QFile(path); } return nullptr; } static QJsonDocument loadJsonFile(QIODevice *data) { if (!data->open(QIODevice::ReadOnly)) { if (auto file = qobject_cast(data)) { qCDebug(cfLog, "Falied on open file: \"%s\", error message: \"%s\"", qPrintable(file->fileName()), qPrintable(file->errorString())); } return QJsonDocument(); } QJsonParseError error; auto document = QJsonDocument::fromJson(data->readAll(), &error); data->close(); if (error.error != QJsonParseError::NoError) { qCWarning(cfLog, "%s", qPrintable(error.errorString())); return QJsonDocument(); } return document; } static DConfigFile::Version parseVersion(const QJsonObject &obj) { DConfigFile::Version version {0, 0}; const QString &verStr = obj[QLatin1String("version")].toString(); if (verStr.isEmpty()) { return version; } const QStringList &items = verStr.split(QLatin1Char('.')); if (items.size() != 2) return version; bool ok = false; quint16 major = items.first().toUShort(&ok); if (!ok) return version; quint16 minor = items.last().toUShort(&ok); if (!ok) return version; version.major = major; version.minor = minor; return version; } #define MAGIC_META QLatin1String("dsg.config.meta") #define MAGIC_OVERRIDE QLatin1String("dsg.config.override") #define MAGIC_CACHE QLatin1String("dsg.config.cache") static const uint InvalidUID = 0xFFFF; inline static bool checkMagic(const QJsonObject &obj, QLatin1String request) { return obj[QLatin1String("magic")].toString() == request; } inline static bool versionIsValid(const DConfigFile::Version &v) { return v.major > 0 || v.minor > 0; } inline static bool checkVersion(const QJsonObject &obj, const DConfigFile::Version &request) { const DConfigFile::Version &v = parseVersion(obj); return versionIsValid(v) && v.major == request.major; } inline void overrideValue(QLatin1String subkey, const QJsonValue &from, QVariantHash &target) { const QJsonValue &v = from[subkey]; if (!v.isUndefined()) target[subkey] = v.toVariant(); } inline static QString getUserName(const uint uid) { passwd *pw = getpwuid(uid); return pw ? QString::fromLocal8Bit(pw->pw_name) : QString(); } /*! @~english @class Dtk::Core::DConfigFile \inmodule dtkcore @brief Specification configuration file implementation of the interface that the configuration file reads and writes. */ /*! @~english @enum DConfigFile::Flag \value NoOverride When this flag exists , it indicates that this configuration item can't be overwritten (see the override mechanism below for details). Otherwise, the absence of this flag indicates that this configuration item is allowed to be overwritten, If it has a screen setting entry, hide or disable the screen setting entry when this entry is not writable. \value Global When reading or writing such a configuration, the user identity is ignored and the same data is obtained regardless of which user identity the program executes. The write operation will take effect for all users. However, if the corresponding configuration storage directory does not exist or has no write permission, this flag is ignored. */ /*! @~english @enum DConfigFile::Permissions \value ReadOnly Overwrite the configuration item as readonly. \value ReadWrite Overwrite the configuration item as readable and writable. */ /*! @~english @enum DConfigFile::Visibility \value Private For internal program use only, Not visible to the outside world. Such configuration items are completely read and written by the program itself, and can be added, deleted and rewritten at will without compatibility consideration, \value Public External programs are available. Once this type of configuration item is released, ensure that the configuration item is backward compatible during the upgrade of the compatible version. In short, this type of configuration item is only allowed to be deleted or modified when a major version of the program/library is upgraded. The configuration item is changed if any of its permissions, visibility, or flags properties are changed. In addition, you do not need to consider compatibility when modifying the value, name, and description attributes. */ /*! @~english @struct Dtk::Core::DConfigFile::Version \inmodule dtkcore @brief Version Information The content format version of this file. The version number is described by two digits, Profiles with different first digits are incompatible with each other, and profiles with different second digits need to be compatible with each other. A program that reads this profile needs to perform content analysis by version, and when it encounters an incompatible version, it needs to terminate parsing immediately and ignore the file. And write a warning message to the program log, such as "1.0" and "2.0" versions are not compatible, If the parser only supports version 1.0, it should stop parsing when it encounters a 2.0 profile. But if version 1.1 is encountered, execution can continue. When writing to this profile, if an incompatible version is encountered, the current contents need to be cleared before writing, and this field needs to be updated with each write */ DConfigMeta::~DConfigMeta() {} QStringList DConfigMeta::genericMetaDirs(const QString &localPrefix) { QStringList paths; // lower priority is higher. for (auto item: DStandardPaths::paths(DStandardPaths::DSG::DataDir)) { paths.prepend(QDir::cleanPath(QString("%1/%2/configs").arg(localPrefix, item))); } return paths; } QStringList DConfigMeta::applicationMetaDirs(const QString &localPrefix, const QString &appId) { QStringList paths; const auto &dataPaths = genericMetaDirs(localPrefix); paths.reserve(dataPaths.size()); for (auto item : dataPaths) { paths << QString("%1/%2").arg(item, appId); } return paths; } Dtk::Core::DConfigCache::~DConfigCache() {} struct DConfigKey { DConfigKey(const QString &aappId, const QString &afileName, const QString &asubpath) : appId(aappId), fileName(afileName), subpath(asubpath) { } explicit DConfigKey(const DConfigKey &src) : DConfigKey(src.appId, src.fileName, src.subpath) { } DConfigKey &operator = (const DConfigKey &src) { this->appId = src.appId; this->fileName = src.fileName; this->subpath = src.subpath; return *this; } QString appId; QString fileName; QString subpath; }; class Q_DECL_HIDDEN DConfigInfo { public: DConfigInfo() { } DConfigInfo(const DConfigInfo &other) { this->values = other.values; } DConfigInfo operator = (const DConfigInfo &other) { this->values = other.values; return *this; } inline static bool checkSerial(const int metaSerial, const int cacheSerial) { if (cacheSerial < 0) return true; if (metaSerial >= 0 && metaSerial == cacheSerial) return true; return false; } DConfigFile::Visibility visibility(const QString &key) const { DConfigFile::Visibility p = DConfigFile::Private; const auto &tmp = values[key][QLatin1String("visibility")].toString(); if (tmp == QLatin1String("public")) p = DConfigFile::Public; return p; } DConfigFile::Permissions permissions(const QString &key) const { DConfigFile::Permissions p = DConfigFile::ReadOnly; const auto &tmp = values[key][QLatin1String("permissions")].toString(); if (tmp == QLatin1String("readwrite")) p = DConfigFile::ReadWrite; return p; } DConfigFile::Flags flags(const QString &key) const { DConfigFile::Flags flags = {}; const auto &tmp = values[key][QLatin1String("flags")]; Q_FOREACH(const QString &flag, tmp.toStringList()) { if (flag == QLatin1String("nooverride")) { flags |= DConfigFile::NoOverride; } else if (flag == QLatin1String("global")) { flags |= DConfigFile::Global; } else if (flag == QLatin1String("user-public")) { flags |= DConfigFile::UserPublic; } } return flags; } QString displayName(const QString &key, const QLocale &locale) const { if (locale == QLocale::AnyLanguage) return values[key][QLatin1String("name")].toString(); return values[key].value(QString("name[%1]") .arg(locale.name())).toString(); } QString description(const QString &key, const QLocale &locale) const { if (locale == QLocale::AnyLanguage) return values[key][QLatin1String("description")].toString(); return values[key].value(QString("description[%1]") .arg(locale.name())).toString(); } inline QVariant value(const QString &key) const { return values[key][QLatin1String("value")]; } inline int serial(const QString &key) const { bool status = false; const int tmp = values[key][QLatin1String("serial")].toInt(&status); if (status) { return tmp; } return -1; } inline void setValue(const QString &key, const QVariant &value) { values[key]["value"] = value; } inline void setSerial(const QString &key, const int &value) { values[key]["serial"] = value; } inline void setTime(const QString &key, const QString &value) { values[key]["time"] = value; } inline void setUser(const QString &key, const uint &value) { values[key]["user"] = getUserName(value); } inline void setAppId(const QString &key, const QString &value) { values[key]["appid"] = value; } inline QStringList keyList() const { return values.keys(); } inline bool contains(const QString &key) const { return values.contains(key); } inline void remove(const QString &key) { values.remove(key); } inline bool update(const QString &key, const QVariantHash &value) { if (!value.contains("value")) { return false; } values[key] = value; return true; } inline bool updateValue(const QString &key, const QJsonValue &value) { return overrideValue(key, "value", value); } inline void updateSerial(const QString &key, const QJsonValue &value) { overrideValue(key, "serial", value); } inline void updatePermissions(const QString &key, const QJsonValue &value) { overrideValue(key, "permissions", value); } QJsonObject content() const { QJsonObject contents; for (auto i = values.constBegin(); i != values.constEnd(); ++i) { contents[i.key()] = QJsonObject::fromVariantHash(i.value()); } return contents; } private: bool overrideValue(const QString &key, const QString &subkey, const QJsonValue &from) { const QJsonValue &v = from[subkey]; if (v.isUndefined()) { return false; } values[key][subkey] = v.toVariant(); return true; } QHash values; }; /*! @~english @class Dtk::Core::DConfigMeta \inmodule dtkcore @brief Provides a prototype of the configuration file and an access interface to the override mechanism. */ /*! @~english @fn DConfigFile::Version DConfigMeta::version() const = 0; @brief Returns configuration version information. @return */ /*! @~english @fn void DConfigMeta::setVersion(quint16 major, quint16 minor) = 0; @brief Sets configuration version information \a major Major version number \a minor Minor version number */ /*! @~english @fn bool DConfigMeta::load(const QString &localPrefix = QString()) = 0; @brief Parsing configuration files \a localPrefix Directory prefix @return */ /*! @~english @fn bool DConfigMeta::load(QIODevice *meta, const QList &overrides) = 0; @brief Parse the configuration file stream \a meta Prototype stream \a overrides The file stream to find for the override mechanism @return */ /*! @~english @fn QStringList DConfigMeta::keyList() const = 0; @brief Returns all configuration items for the configuration content @return */ /*! @~english @fn DConfigFile::Flags DConfigMeta::flags(const QString &key) const = 0; @brief Returns the attribute of the specified configuration item \a key Configure the name of the option, NoOverride This option can't be overridden, and Global ignores the user identity @return */ /*! @~english @fn DConfigFile::Permissions DConfigMeta::permissions(const QString &key) const = 0; @brief Returns the permission for the specified configuration item \a key Configuration name @return */ /*! @~english @fn DConfigFile::Visibility DConfigMeta::visibility(const QString &key) const = 0; @brief Returns the visibility of the specified configuration item \a key Configuration name @return */ /*! @~english @fn int DConfigMeta::serial(const QString &key) const = 0; @brief Returns a monotonically increasing value of a configuration item \a key Configuration name @return An invalid value of -1 indicates that the entry is not configured */ /*! @~english @fn QString DConfigMeta::displayName(const QString &key, const QLocale &locale) = 0; @brief Returns the display name of the specified configuration \a key Configuration name \a locale Language version @return */ /*! @~english @fn QString DConfigMeta::description(const QString &key, const QLocale &locale) = 0; @brief Returns a description of the specified configuration item \a key Configuration name \a locale Language version @return */ /*! @~english @fn QString DConfigMeta::metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0; @brief Returns the path to the profile \a localPrefix Directory of all override mechanisms that need to be searched @return */ /*! @~english @fn QStringList DConfigMeta::allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0; @brief Gets all the override mechanism directories to look for for the \a prefix directory \a useAppId Whether not to use the generic directory @return */ /*! @~english @fn QVariant DConfigMeta::value(const QString &key) const = 0; @brief Original value of meta overwritten by the overwriting mechanism \a key Configuration name @return */ class Q_DECL_HIDDEN DConfigMetaImpl : public DConfigMeta { // DConfigMeta interface public: explicit DConfigMetaImpl(const DConfigKey &configKey); virtual ~DConfigMetaImpl() override; inline virtual QStringList keyList() const override { return values.keyList(); } inline virtual DConfigFile::Flags flags(const QString &key) const override { return values.flags(key); } inline virtual DConfigFile::Permissions permissions(const QString &key) const override { return values.permissions(key); } inline virtual DConfigFile::Visibility visibility(const QString &key) const override { return values.visibility(key); } inline virtual int serial(const QString &key) const override { return values.serial(key); } inline virtual QString description(const QString &key, const QLocale &locale) override { return values.description(key, locale); } virtual DConfigFile::Version version() const override { return m_version; } inline virtual void setVersion(quint16 major, quint16 minor) override { m_version.major = major; m_version.minor = minor; } inline virtual QString displayName(const QString &key, const QLocale &locale) override { return values.displayName(key, locale); } inline virtual QVariant value(const QString &key) const override { return values.value(key); } QString metaPath(const QString &localPrefix, bool *useAppId) const override { bool useAppIdForOverride = true; QString path; const QStringList &applicationMetas = applicationMetaDirs(localPrefix, configKey.appId); for (auto iter = applicationMetas.rbegin(); iter != applicationMetas.rend(); iter++) { path = getFile(*iter, configKey.subpath, configKey.fileName + FILE_SUFFIX); if (!path.isEmpty()) break; } if (path.isEmpty()) { useAppIdForOverride = false; const QStringList &genericnMetas = genericMetaDirs(localPrefix); for (auto iter = genericnMetas.rbegin(); iter != genericnMetas.rend(); iter++) { path = getFile(*iter, configKey.subpath, configKey.fileName + FILE_SUFFIX); if (!path.isEmpty()) break; } } if (useAppId) { *useAppId = useAppIdForOverride; } return path; } bool load(const QString &localPrefix) override { if (!isValidAppId(configKey.appId)) { qCWarning(cfLog, "AppId is invalid, appId=%s", qPrintable(configKey.appId)); return false; } if (!isValidFilename(configKey.fileName)) { qCWarning(cfLog, "Name is invalid, filename=%s", qPrintable(configKey.fileName)); return false; } bool useAppIdForOverride = true; QString path = metaPath(localPrefix, &useAppIdForOverride); if (path.isEmpty()) { qCWarning(cfLog, "Can't load meta file from local prefix: \"%s\"", qPrintable(localPrefix)); return false; } QScopedPointer meta(new QFile(path)); struct _ScopedPointer { explicit _ScopedPointer(const QList &list) : m_list(list) {} ~_ScopedPointer() {qDeleteAll(m_list);} QList m_list; }; _ScopedPointer overrides(loadOverrides(localPrefix, useAppIdForOverride)); return load(meta.data(), overrides.m_list); } bool load(QIODevice *meta, const QList &overrides) override { { const QJsonDocument &doc = loadJsonFile(meta); if (!doc.isObject()) return false; // 检查标识 const QJsonObject &root = doc.object(); if (!checkMagic(root, MAGIC_META)) { qCWarning(cfLog, "The meta magic does not match"); return false; } // 检查版本兼容性 const auto &v = parseVersion(root); if (!versionIsValid(v) || v.major > DConfigFile::supportedVersion().major) { qCWarning(cfLog, "The meta version number does not match, " "the file major version=%i, supported major version<=%i", v.major, DConfigFile::supportedVersion().major); return false; } m_version = v; const auto &contents = root[QLatin1String("contents")].toObject(); auto i = contents.constBegin(); // 初始化原始值 for (; i != contents.constEnd(); ++i) { if (!values.update(i.key(), i.value().toObject().toVariantHash())) { qWarning() << "key:" << i.key() << "has no value"; return false; } } } // for override Q_FOREACH(auto override, overrides) { const QJsonDocument &doc = loadJsonFile(override); if (doc.isObject()) { const QJsonObject &root = doc.object(); if (!checkMagic(root, MAGIC_OVERRIDE)) { if (auto file = static_cast(override)) { qCWarning(cfLog, "The override magic does not match, file: \"%s\", error message: \"%s\"", qPrintable(file->fileName()), qPrintable(file->errorString())); } else { qCWarning(cfLog, "The override magic does not match"); } break; //TODO don't continue parse? } if (!checkVersion(root, m_version)) { qCWarning(cfLog, "The override version number does not match"); break; } if (auto file = static_cast(override)) { qCDebug(cfLog, "The override will be applied, file: \"%s\"", qPrintable(file->fileName())); } const auto &contents = root[QLatin1String("contents")].toObject(); auto i = contents.constBegin(); for (; i != contents.constEnd(); ++i) { if (!values.contains(i.key())) { qCWarning(cfLog, "The meta doesn't contain the override key: \"%s\".", qPrintable(i.key())); continue; } // 检查是否允许 override if (values.flags(i.key()) & DConfigFile::NoOverride) continue; if (!values.updateValue(i.key(), i.value())) { qWarning() << "key (override):" << i.key() << "has no value"; return false; } values.updateSerial(i.key(), i.value()); values.updatePermissions(i.key(), i.value()); } } } return true; } /*! @~english \internal @brief 获得前缀为 \a prefix 目录的应用或公共库的所有覆盖机制目录,越后优先级越高 */ inline QStringList overrideDirs(const QString & prefix, bool useAppId) const { const QString &path2 = QString("%1/etc/dsg/configs/overrides/%2/%3") .arg(prefix, useAppId ? configKey.appId : QString(), configKey.fileName); QStringList paths; const QStringList &dataPaths = DStandardPaths::paths(DStandardPaths::DSG::DataDir); paths.reserve(dataPaths.size() + 1); for (auto path: dataPaths) { // reverse `DataDir`'s paths, previous `DataDir`'s value has high priority paths.prepend(QString("%1%2/configs/overrides/%3/%4") .arg(prefix, path, useAppId ? configKey.appId : QString(), configKey.fileName)); } // 在后面的优先级更高 paths.append(path2); return paths; } inline QStringList allOverrideDirs(const bool useAppId, const QString &prefix) const override { QStringList dirs; // 只有当允许不使用 appid 时才能回退到通用目录 if (!useAppId) { dirs << overrideDirs(prefix, false); } // 无论如何都先从带 appid 的目录下加载override文件 // 在列表后面的更优先 dirs << overrideDirs(prefix, true); return dirs; } /*! @~english \internal @brief 获得所有遵守覆盖机制的文件流 在override文件放置路径下按优先级查找覆盖文件,支持子目录查找机制, 使用自然排序(如“a2”在“a11”之前)规则按文件名进行排序 */ QList loadOverrides(const QString &prefix, bool useAppId) const { auto filters = QDir::Files | QDir::NoDotAndDotDot | QDir::Readable; const QStringList nameFilters {"*" + FILE_SUFFIX}; QStringList dirs = allOverrideDirs(useAppId, prefix); QList list; list.reserve(50); QCollator collator(QLocale::English); collator.setNumericMode(true); collator.setIgnorePunctuation(true); Q_FOREACH(const auto &dir, dirs) { const QDir base_dir(QDir::cleanPath(dir)); if (!base_dir.exists()) continue; if (!subpathIsValid(configKey.subpath, base_dir)) continue; QDir target_dir = base_dir; target_dir.setFilter(filters); target_dir.setNameFilters(nameFilters); if (!configKey.subpath.isEmpty()) target_dir.cd(configKey.subpath.mid(1)); do { qCDebug(cfLog, "load override file from: \"%s\"", qPrintable(target_dir.path())); QDirIterator iterator(target_dir); QList sublist; sublist.reserve(50); while(iterator.hasNext()) { sublist.append(new QFile(iterator.next())); } // 从小到大排序 std::sort(sublist.begin(), sublist.end(), [&collator](QIODevice *f1, QIODevice *f2){ if (collator.compare(static_cast(f1)->fileName(), static_cast(f2)->fileName()) < 0) return true; return false; }); list = sublist + list; if (base_dir.path() == target_dir.path()) break; } while (target_dir.cdUp()); } return list; } DConfigKey configKey; DConfigInfo values; DConfigFile::Version m_version = {0, 0}; char padding [4] = {}; }; DConfigMetaImpl::DConfigMetaImpl(const DConfigKey &configKey) : DConfigMeta (), configKey(configKey) { } DConfigMetaImpl::~DConfigMetaImpl() { } /*! @~english @class Dtk::Core::DConfigCache \inmodule dtkcore @brief Provides user and global runtime cache access interfaces for Configuration file. */ /*! @~english @fn bool DConfigCache::load(const QString &localPrefix = QString()) = 0; @brief Parse the cache configuration file @return */ /*! @~english @fn bool DConfigCache::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0; @brief Save the cached value to disk \a localPrefix Directory prefix \a format Save format \a sync Whether to refresh immediately @return */ /*! @~english @fn bool DConfigCache::isGlobal() const = 0; @brief Whether to cache globally @return */ /*! @~english @fn void DConfigCache::remove(const QString &key) = 0; @brief Delete a configuration entry from the cache \a key Configuration name @return */ /*! @~english @fn QStringList DConfigCache::keyList() const = 0; @brief Returns all configuration items for the configuration content @return */ /*! @~english @fn bool DConfigCache::setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &callerAppid) = 0; @brief Sets the value in the cache \a key Configuration name \a value Configuration name \a uid User Id at setup time \a callerAppid Application id at setup time @return A value of true indicates that the new value has been reset, and false indicates that it has not been set */ /*! @~english @fn QVariant DConfigCache::value(const QString &key) const = 0; @brief Get the value in the cache \a key Configuration name @return */ /*! @~english @fn int DConfigCache::serial(const QString &key) const = 0; @brief Returns a monotonically increasing value of a configuration item \a key Configuration name @return An invalid value of -1 indicates that the entry is not configured */ /*! @~english @fn uint DConfigCache::uid() const = 0; @brief User identification, when used in the global cache, uid is a specific value for non-user identification @return */ /*! @~english @fn void setCachePathPrefix(const QString &prefix) = 0; @brief Set cache's prefix path, it's access permissions is considered by caller, and it needs to distinguish the paths of different caches by caller. @param prefix cache's prefix path. */ class Q_DECL_HIDDEN DConfigCacheImpl : public DConfigCache { public: DConfigCacheImpl(const DConfigKey &configKey, const uint uid, bool global); virtual ~DConfigCacheImpl() override; // DConfigCache interface public: inline virtual int serial(const QString &key) const override { return values.serial(key); } inline virtual uint uid() const override { return userid; } inline virtual QStringList keyList() const override { return values.keyList(); } inline QString applicationCacheDir(const QString &localPrefix, const QString &suffix) const { QString prefix(cachePrefix); if (prefix.isEmpty()) { // If target user is current user or system user, then get the home path by environment variable first. QString homePath; if (userid == InvalidUID || (getuid() == userid)) { homePath = DStandardPaths::homePath(); } else { homePath = DStandardPaths::homePath(getuid()); } if (homePath.isEmpty()) return QString(); // fallback to default application cache directory. prefix = homePath + QStringLiteral("/.config/dsg/configs"); } return QDir::cleanPath(QString("%1/%2/%3").arg(localPrefix, prefix + suffix, configKey.appId)); } inline QString applicationCacheDir(const QString &localPrefix) const { return applicationCacheDir(localPrefix, QString()); } inline QString cacheDir(const QString &basePath) { QDir dir(basePath + configKey.subpath); return dir.filePath(configKey.fileName + FILE_SUFFIX); } inline QString globalCacheDir(const QString &localPrefix) const { QString prefix(cachePrefix); if (prefix.isEmpty()) { // TODO `DSG_APP_DATA` is not set and `appid` is not captured in `DStandardPaths::path`. QString appDataDir = DStandardPaths::path(DStandardPaths::DSG::AppData); if (appDataDir.isEmpty()) { #ifdef D_DSG_APP_DATA_FALLBACK appDataDir = QStringLiteral(D_DSG_APP_DATA_FALLBACK); QFileInfo tmp(appDataDir); if (!tmp.exists() && !tmp.isSymLink() && !QDir::current().mkpath(appDataDir)) { qCDebug(cfLog, "Not found a valid DSG_APP_DATA directory"); return QString(); } #else return QString(); #endif } // fallback to default global cache directory. prefix = QString("%1/configs").arg(appDataDir); } return QDir::cleanPath(QString("%1/%2/%3").arg(localPrefix, prefix, configKey.appId)); } QString getCacheDir(const QString &localPrefix = QString()) { if (isGlobal()) { const QString &dir = globalCacheDir(localPrefix); if (!dir.isEmpty()) return dir; // Not supported the global config, fallback the config cache data to user directory. return applicationCacheDir(localPrefix, "-fake-global"); } else { return applicationCacheDir(localPrefix); } } bool load(const QString &localPrefix = QString()) override; bool isGlobal() const override { return global; } inline void remove(const QString &key) override { values.remove(key); cacheChanged = true; } bool setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &appid) override { if (values.value(key) == value) { return false; } values.setValue(key, value); values.setSerial(key, serial); values.setTime(key, QDateTime::currentDateTime().toString(Qt::ISODate)); values.setUser(key, uid); values.setAppId(key, appid.isEmpty() ? configKey.appId : appid); cacheChanged = true; return true; } inline QVariant value(const QString &key) const override { return values.value(key); } bool save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) override; virtual void setCachePathPrefix(const QString &prefix) override { cachePrefix = prefix; } DConfigKey configKey; DConfigInfo values; QString cachePrefix; uint userid; bool global; bool cacheChanged = false; }; DConfigCacheImpl::DConfigCacheImpl(const DConfigKey &configKey, const uint uid, bool global) : DConfigCache(), configKey(configKey), userid(uid), global(global) { } DConfigCacheImpl::~DConfigCacheImpl() { } bool DConfigCacheImpl::load(const QString &localPrefix) { // cache 文件要严格匹配 subpath const QString &dir = getCacheDir(localPrefix); if (dir.isEmpty()) { return true; } QScopedPointer cache(loadFile(dir, configKey.subpath, configKey.fileName + FILE_SUFFIX, false)); if (!cache) { return true; } const QJsonDocument &doc = loadJsonFile(cache.data()); if (doc.isObject()) { const QJsonObject &root = doc.object(); if (!checkMagic(root, MAGIC_CACHE)) return false; if (!checkVersion(root, DConfigFile::supportedVersion())) return false; auto &&contents = root[QLatin1String("contents")].toObject(); auto i = contents.constBegin(); // 原样保存原始数据 for (; i != contents.constEnd(); ++i) { values.update(i.key(), i.value().toObject().toVariantHash()); } } return true; } bool DConfigCacheImpl::save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) { if (!cacheChanged) return true; cacheChanged = false; const QString &dir = getCacheDir(localPrefix); if (dir.isEmpty()) { qCWarning(cfLog, "Falied on saveing, the config cache directory is empty for the user[%d], " "the current user[%d].", userid, getuid()); return false; } QString path = cacheDir(dir); QFile cache(path); if (!QFile::exists(QFileInfo(cache.fileName()).path())) { QDir().mkpath(QFileInfo(cache.fileName()).path()); } if (!cache.open(QIODevice::WriteOnly)) { qCWarning(cfLog, "Falied on saveing data when open file: \"%s\", error message: \"%s\"", qPrintable(cache.fileName()), qPrintable(cache.errorString())); return false; } qCDebug(cfLog, "Save cache file \"%s\".", qPrintable(cache.fileName())); QJsonObject root; root[QLatin1String("magic")] = MAGIC_CACHE; const DConfigFile::Version version = DConfigFile::supportedVersion(); root[QLatin1String("version")] = QString("%1.%2").arg(version.major) .arg(version.minor); root[QLatin1String("contents")] = values.content(); QJsonDocument doc; doc.setObject(root); const QByteArray &json = doc.toJson(format); bool status = cache.write(json) == json.size(); if (status && sync) { cache.flush(); } return status; } class Q_DECL_HIDDEN DConfigFilePrivate : public DObjectPrivate { public: DConfigFilePrivate(DConfigFile *qq, const QString &appId, const QString &name, const QString &subpath) : DObjectPrivate(qq), configKey(appId, name ,subpath), configMeta(new DConfigMetaImpl(configKey)) { } DConfigFilePrivate(DConfigFile *qq, const DConfigKey &configKey) : DObjectPrivate(qq), configKey(configKey), configMeta(new DConfigMetaImpl(configKey)) { } ~DConfigFilePrivate() override; bool load(const QString &localPrefix) { bool status = configMeta->load(localPrefix); if (status) { // for cache status &= globalCache->load(localPrefix); } return status; } bool setValue(const QString &key, const QVariant &value, DConfigCache *userCache, const QString &appid) { // 此处不要检查权限,在获取 value 时会检查 if (auto cache = getCache(key, userCache)) { if (!value.isValid()) { cache->remove(key); return true; } else { const auto &metaValue = configMeta->value(key); // sample judgement to reduce a copy of convert. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) if (metaValue.typeId() == value.typeId()) return cache->setValue(key, value, configMeta->serial(key), cache->uid(), appid); // convert copy to meta's type, it promises `setValue` don't change meta's type. // canConvert isn't explicit, e.g: QString is also can convert to double. auto copy = value; if (!copy.convert(metaValue.metaType())) { qCWarning(cfLog) << "check type error, meta type is " << metaValue.metaType().name() << ", and now type is " << value.metaType().name(); return false; } // TODO it's a bug of qt, MetaType of 1.0 is qlonglong instead of double in json file. static const QVector filterConvertType { QMetaType{QMetaType::Double} }; // reset to origin value. if (filterConvertType.contains(value.metaType())) { copy = value; } #else if (metaValue.type() == value.type()) return cache->setValue(key, value, configMeta->serial(key), cache->uid(), appid); auto copy = value; if (!copy.convert(metaValue.userType())) { qCWarning(cfLog) << "check type error, meta type is " << metaValue.type() << ", and now type is " << value.type(); return false; } static const QVector filterConvertType { QVariant::Double }; if (filterConvertType.contains(value.type())) { copy = value; } #endif return cache->setValue(key, copy, configMeta->serial(key), cache->uid(), appid); } } return false; } DConfigCache* getCache(const QString &key, DConfigCache *userCache) const { if(configMeta->flags(key).testFlag(DConfigFile::Global)) { return globalCache; } return userCache; } QVariant cacheValue(DConfigCache *userCache, const QString &key) const { // 检查权限 if (configMeta->permissions(key) != DConfigFile::ReadOnly) { if (auto cache = getCache(key, userCache)) { if (DConfigInfo::checkSerial(configMeta->serial(key), cache->serial(key))) { const QVariant &tmp = cache->value(key); if (tmp.isValid()) return tmp; } } } return QVariant(); } QVariant value(const QString &key, DConfigCache *userCache) const { const QVariant &v = cacheValue(userCache, key); if (v.isValid()) return v; return configMeta->value(key); } D_DECLARE_PUBLIC(DConfigFile) private: DConfigCacheImpl* globalCache; DConfigKey configKey; DConfigMeta *configMeta; }; DConfigFilePrivate::~DConfigFilePrivate() { if (globalCache) { delete globalCache; globalCache = nullptr; } if (configMeta) { delete configMeta; configMeta = nullptr; } } /*! @~english @brief Supported versions @return */ constexpr DConfigFile::Version DConfigFile::supportedVersion() { return DConfigFile::Version{1, 0}; } /*! @~english @brief 构造配置文件管理对象 \a appId Application unique identification \a name Config filename \a subpath Subdirectories */ DConfigFile::DConfigFile(const QString &appId, const QString &name, const QString &subpath) : DObject(*new DConfigFilePrivate(this, appId, name, subpath)) { D_D(DConfigFile); d->globalCache = new DConfigCacheImpl(d->configKey, InvalidUID, true); } DConfigFile::DConfigFile(const DConfigFile &other) : DObject(*new DConfigFilePrivate(this, other.d_func()->configKey)) { D_D(DConfigFile); auto cache = new DConfigCacheImpl(d->configKey, InvalidUID, true); cache->values = other.d_func()->globalCache->values; d->globalCache = cache; } /*! @~english @brief Parse configuration files \a localPrefix Directory prefix @return */ bool DConfigFile::load(const QString &localPrefix) { D_D(DConfigFile); return d->load(localPrefix); } /*! @~english @brief Parse the profile stream \a meta Prototype stream \a overrides File stream to find for the override mechanism @return */ bool DConfigFile::load(QIODevice *meta, const QList &overrides) { return this->meta()->load(meta, overrides); } /*! @~english @brief Save the cached value to disk \a format Save format \a sync Whether to refresh immediately @return */ bool DConfigFile::save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) const { D_DC(DConfigFile); bool ok = d->globalCache->save(localPrefix, format, sync); return ok; } /*! @~english * @brief DConfigFile::value * @param key Configuration name * @param userCache Specific user cache, \a userCache is unused when the key is global * @return */ QVariant DConfigFile::value(const QString &key, DConfigCache *userCache) const { D_DC(DConfigFile); return d->value(key, userCache); } /*! * \brief DConfigFile::cacheValue Get a specific user cache's value * \param userCache Specific user cache, it is unused if the \a key is global configuration item * \param key Configuration name * \return */ QVariant DConfigFile::cacheValue(DConfigCache *userCache, const QString &key) const { D_DC(DConfigFile); return d->cacheValue(userCache, key); } /*! @~english @brief Sets the value in the cache \a key Configuration name \a value The value to set \a userCache Specific user cache at setup time \a appid Application id at setup time @return A value of true indicates that the new value has been reset, and false indicates that it has not been set */ bool DConfigFile::setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache) { D_D(DConfigFile); return d->setValue(key, value, userCache, callerAppid); } DConfigCache *DConfigFile::createUserCache(const uint uid) { D_D(DConfigFile); return new DConfigCacheImpl(d->configKey, uid, false); } /*! @~english @brief Return to the global cache @return */ DConfigCache *DConfigFile::globalCache() const { D_DC(DConfigFile); return d->globalCache; } /*! @~english @brief Return the prototype object @return */ DConfigMeta *DConfigFile::meta() { D_D(DConfigFile); return d->configMeta; } /*! @~english @brief Checks whether the configuration file is valid @return */ bool DConfigFile::isValid() const { D_DC(DConfigFile); return versionIsValid(d->configMeta->version()); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/ddesktopentry.cpp000066400000000000000000001014231476226660600174530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddesktopentry.h" #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE enum { Space = 0x1, Special = 0x2 }; static const char charTraits[256] = { // Space: '\t', '\n', '\r', ' ' // Special: '\n', '\r', ';', '=', '\\', '#' // Please note that '"' is NOT a special character 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, 0, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; bool readLineFromData(const QByteArray &data, int &dataPos, int &lineStart, int &lineLen, int &equalsPos) { int dataLen = data.length(); equalsPos = -1; lineStart = dataPos; while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space)) ++lineStart; int i = lineStart; while (i < dataLen) { while (!(charTraits[uint(uchar(data.at(i)))] & Special)) { if (++i == dataLen) goto break_out_of_outer_loop; } char ch = data.at(i++); if (ch == '=') { if (equalsPos == -1) equalsPos = i - 1; } else if (ch == '\n' || ch == '\r') { if (i == lineStart + 1) { ++lineStart; } else { --i; goto break_out_of_outer_loop; } } else if (ch == '\\') { if (i < dataLen) { char ch = data.at(i++); if (i < dataLen) { char ch2 = data.at(i); // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n')) ++i; } } } else if (ch == ';') { // The multiple values should be separated by a semicolon and the value of the key // may be optionally terminated by a semicolon. Trailing empty strings must always // be terminated with a semicolon. Semicolons in these values need to be escaped // using \; . // Don't need to do anything here. } else { Q_ASSERT(ch == '#'); if (i == lineStart + 1) { char ch; while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r')) ++i; lineStart = i; } } } break_out_of_outer_loop: dataPos = i; lineLen = i - lineStart; return lineLen > 0; } QString &doEscape(QString& str, const QHash &repl) { // First we replace slash. str.replace(QLatin1Char('\\'), QLatin1String("\\\\")); QHashIterator i(repl); while (i.hasNext()) { i.next(); if (i.key() != QLatin1Char('\\')) str.replace(i.key(), QString::fromLatin1("\\\\%1").arg(i.value())); } return str; } QString &doUnescape(QString& str, const QHash &repl) { int n = 0; while (1) { n=str.indexOf(QLatin1String("\\"), n); if (n < 0 || n > str.length() - 2) break; if (repl.contains(str.at(n+1))) { str.replace(n, 2, repl.value(str.at(n+1))); } n++; } return str; } /*! \internal */ class DDesktopEntrySection { public: DDesktopEntrySection() {} QString name; QMap valuesMap; QByteArray unparsedDatas; int sectionPos = 99; inline operator QString() const { return QLatin1String("DDesktopEntrySection(") + name + QLatin1String(")"); } QByteArray sectionData() const { if (unparsedDatas.isEmpty()) { // construct data and return QByteArray data; data.append(QString("[%1]\n").arg(name).toLocal8Bit()); QMap::const_iterator i; for (i = valuesMap.begin(); i != valuesMap.end(); i++) { data.append(QString("%1=%2\n").arg(i.key(), i.value()).toLocal8Bit()); } return data; } else { return unparsedDatas; } } bool ensureSectionDataParsed() { if (unparsedDatas.isEmpty()) return true; valuesMap.clear(); // for readLineFromFileData() int dataPos = 0; int lineStart; int lineLen; int equalsPos; while(readLineFromData(unparsedDatas, dataPos, lineStart, lineLen, equalsPos)) { if (unparsedDatas.at(lineStart) == '[') continue; // section name already parsed if (equalsPos != -1) { QString key = unparsedDatas.mid(lineStart, equalsPos - lineStart).trimmed(); QString rawValue = unparsedDatas.mid(equalsPos + 1, lineStart + lineLen - equalsPos - 1).trimmed(); valuesMap[key] = rawValue; } } unparsedDatas.clear(); return true; } bool contains(const QString &key) const { const_cast(this)->ensureSectionDataParsed(); return valuesMap.contains(key); } QStringList allKeys() const { const_cast(this)->ensureSectionDataParsed(); return valuesMap.keys(); } QString get(const QString &key, QString &defaultValue) { if (this->contains(key)) { return valuesMap[key]; } else { return defaultValue; } } bool set(const QString &key, const QString &value) { if (this->contains(key)) { valuesMap.remove(key); } valuesMap[key] = value; return true; } bool remove(const QString &key) { if (this->contains(key)) { valuesMap.remove(key); return true; } return false; } }; typedef QMap SectionMap; class DDesktopEntryPrivate { public: DDesktopEntryPrivate(const QString &filePath, DDesktopEntry *qq); ~DDesktopEntryPrivate(); bool isWritable() const; bool fuzzyLoad(); bool initSectionsFromData(const QByteArray &data); void setStatus(const DDesktopEntry::Status &newStatus) const; bool write(QIODevice &device) const; int sectionPos(const QString §ionName) const; bool contains(const QString §ionName, const QString &key) const; QStringList keys(const QString §ionName) const; bool get(const QString §ionName, const QString &key, QString *value); bool set(const QString §ionName, const QString &key, const QString &value); bool remove(const QString §ionName, const QString &key); protected: QString filePath; QMutex fileMutex; SectionMap sectionsMap; mutable DDesktopEntry::Status status; private: bool __padding[4]; DDesktopEntry *q_ptr = nullptr; Q_DECLARE_PUBLIC(DDesktopEntry) }; DDesktopEntryPrivate::DDesktopEntryPrivate(const QString &filePath, DDesktopEntry *qq) : filePath(filePath), q_ptr(qq) { fuzzyLoad(); } DDesktopEntryPrivate::~DDesktopEntryPrivate() { } bool DDesktopEntryPrivate::isWritable() const { QFileInfo fileInfo(filePath); #ifndef QT_NO_TEMPORARYFILE if (fileInfo.exists()) { #endif QFile file(filePath); return file.open(QFile::ReadWrite); #ifndef QT_NO_TEMPORARYFILE } else { // Create the directories to the file. QDir dir(fileInfo.absolutePath()); if (!dir.exists()) { if (!dir.mkpath(dir.absolutePath())) return false; } // we use a temporary file to avoid race conditions QTemporaryFile file(filePath); return file.open(); } #endif } bool DDesktopEntryPrivate::fuzzyLoad() { QFile file(filePath); QFileInfo fileInfo(filePath); if (fileInfo.exists() && !file.open(QFile::ReadOnly)) { setStatus(DDesktopEntry::AccessError); return false; } if (file.isReadable() && file.size() != 0) { bool ok = false; QByteArray data = file.readAll(); ok = initSectionsFromData(data); if (!ok) { setStatus(DDesktopEntry::FormatError); return false; } } setStatus(DDesktopEntry::NoError); return true; } bool DDesktopEntryPrivate::initSectionsFromData(const QByteArray &data) { sectionsMap.clear(); QString lastSectionName; int lastSectionStart = 0; bool formatOk = true; int sectionIdx = 0; // for readLineFromFileData() int dataPos = 0; int lineStart; int lineLen; int equalsPos; auto commitSection = [=](const QString &name, int sectionStartPos, int sectionLength, int sectionIndex) { DDesktopEntrySection lastSection; lastSection.name = name; lastSection.unparsedDatas = data.mid(sectionStartPos, sectionLength); lastSection.sectionPos = sectionIndex; sectionsMap[name] = lastSection; }; // TODO: here we only need to find the section start, so things like equalsPos are useless here. // maybe we can do some optimization here via adding extra argument to readLineFromData(). while(readLineFromData(data, dataPos, lineStart, lineLen, equalsPos)) { // qDebug() << "CurrentLine:" << data.mid(lineStart, lineLen); if (data.at(lineStart) == '[') { // commit the last section we've ever read before we read the new one. if (!lastSectionName.isEmpty()) { commitSection(lastSectionName, lastSectionStart, lineStart - lastSectionStart, sectionIdx); sectionIdx++; } // process section name line QByteArray sectionName; int idx = data.indexOf(']', lineStart); if (idx == -1 || idx >= lineStart + lineLen) { qWarning() << "Bad desktop file format while reading line:" << data.mid(lineStart, lineLen); formatOk = false; sectionName = data.mid(lineStart + 1, lineLen - 1).trimmed(); } else { sectionName = data.mid(lineStart + 1, idx - lineStart - 1).trimmed(); } lastSectionName = sectionName; lastSectionStart = lineStart; } } Q_ASSERT(lineStart == data.length()); if (!lastSectionName.isEmpty()) { commitSection(lastSectionName, lastSectionStart, lineStart - lastSectionStart, sectionIdx); } return formatOk; } // Always keep the first meet error status. and allowed clear the status. void DDesktopEntryPrivate::setStatus(const DDesktopEntry::Status &newStatus) const { if (newStatus == DDesktopEntry::NoError || this->status == DDesktopEntry::NoError) { this->status = newStatus; } } bool DDesktopEntryPrivate::write(QIODevice &device) const { Q_Q(const DDesktopEntry); QStringList sortedKeys = q->allGroups(true); for (const QString &key : sortedKeys) { qint64 ret = device.write(sectionsMap[key].sectionData()); if (ret == -1) return false; } return true; } int DDesktopEntryPrivate::sectionPos(const QString §ionName) const { if (sectionsMap.contains(sectionName)) { return sectionsMap[sectionName].sectionPos; } return -1; } bool DDesktopEntryPrivate::contains(const QString §ionName, const QString &key) const { if (sectionName.isNull() || key.isNull()) { return false; } if (sectionsMap.contains(sectionName)) { return sectionsMap[sectionName].contains(key); } return false; } QStringList DDesktopEntryPrivate::keys(const QString §ionName) const { if (sectionName.isNull()) { return {}; } if (sectionsMap.contains(sectionName)) { return sectionsMap[sectionName].allKeys(); } return {}; } // return true if we found the value, and set the value to *value bool DDesktopEntryPrivate::get(const QString §ionName, const QString &key, QString *value) { if (!this->contains(sectionName, key)) { return false; } if (sectionsMap.contains(sectionName)) { QString &&result = sectionsMap[sectionName].get(key, *value); *value = result; return true; } return false; } bool DDesktopEntryPrivate::set(const QString §ionName, const QString &key, const QString &value) { if (sectionsMap.contains(sectionName)) { bool result = sectionsMap[sectionName].set(key, value); return result; } else { // create new section. DDesktopEntrySection newSection; newSection.name = sectionName; newSection.set(key, value); sectionsMap[sectionName] = newSection; return true; } return false; } bool DDesktopEntryPrivate::remove(const QString §ionName, const QString &key) { if (this->contains(sectionName, key)) { return sectionsMap[sectionName].remove(key); } return false; } /*! @~english @class Dtk::Core::DDesktopEntry \inmodule dtkcore @brief Handling desktop entry files. DDesktopEntry provide method for handling XDG desktop entry read and write. The interface of this class is similar to QSettings. For more details about the spec itself, please refer to: https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html */ DDesktopEntry::DDesktopEntry(const QString &filePath) noexcept : d_ptr(new DDesktopEntryPrivate(filePath, this)) { } DDesktopEntry::~DDesktopEntry() { } /*! @~english @brief Write back data to the desktop entry file. @return true if write success; otherwise returns false. */ bool DDesktopEntry::save() const { Q_D(const DDesktopEntry); // write to file. if (d->isWritable()) { bool ok = false; bool createFile = false; QFileInfo fileInfo(d->filePath); #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile) QSaveFile sf(d->filePath); sf.setDirectWriteFallback(true); #else QFile sf(d->filePath); #endif if (!sf.open(QIODevice::WriteOnly)) { d->setStatus(DDesktopEntry::AccessError); return false; } ok = d->write(sf); #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile) if (ok) { ok = sf.commit(); } #endif if (ok) { // If we have created the file, apply the file perms if (createFile) { QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther; QFile(d->filePath).setPermissions(perms); } return true; } else { d->setStatus(DDesktopEntry::AccessError); return false; } } return false; } /*! @~english @brief Get data parse status @return Returns a status code indicating the first error that was met by DDesktopEntry, or QSettings::NoError if no error occurred. Be aware that DDesktopEntry delays performing some operations. */ DDesktopEntry::Status DDesktopEntry::status() const { Q_D(const DDesktopEntry); return d->status; } /*! @~english @brief Get a list of all section keys inside the given \a section. @return all available section keys. */ QStringList DDesktopEntry::keys(const QString §ion) const { Q_D(const DDesktopEntry); if (section.isEmpty()) { qWarning("DDesktopEntry::keys: Empty section name passed"); return {}; } return d->keys(section); } /*! @~english @brief Get a list of all section groups inside the desktop entry. If \a sorted is set to true, the returned result will keep the order as-is when reading the entry file. @return all available section groups. */ QStringList DDesktopEntry::allGroups(bool sorted) const { Q_D(const DDesktopEntry); if (!sorted) { return d->sectionsMap.keys(); } else { using StrIntPair = QPair; QStringList keys = d->sectionsMap.keys(); QList result; for (const QString & key : keys) { result << StrIntPair(key, d->sectionPos(key)); } std::sort(result.begin(), result.end(), [](const StrIntPair& a, const StrIntPair& b) -> bool { return a.second < b.second; }); keys.clear(); for (const StrIntPair& pair : result) { keys << pair.first; } return keys; } } /*! @~english @brief Check if the desktop entry file have the given \a section contains the given \a key @return true if the desktop entry contains the \a key in \a section; otherwise returns false. */ bool DDesktopEntry::contains(const QString &key, const QString §ion) const { Q_D(const DDesktopEntry); if (key.isEmpty() || section.isEmpty()) { qWarning("DDesktopEntry::contains: Empty key or section passed"); return false; } return d->contains(section, key); } /*! @~english @brief Returns the localized string value of the "Name" key under "Desktop Entry" section. It's equivalent to calling localizedValue("Name"). @return Returns the localized string value of the "Name" key under "Desktop Entry" section. @sa localizedValue(), genericName(), ddeDisplayName() */ QString DDesktopEntry::name() const { return localizedValue(QStringLiteral("Name")); } /*! @~english @brief Returns the localized string value of the "GenericName" key under "Desktop Entry" section. It's equivalent to calling localizedValue("GenericName"). It will NOT fallback to "Name" if "GenericName" is not existed. @return Returns the localized string value of the "GenericName" key under "Desktop Entry" section. @sa localizedValue(), name(), ddeDisplayName() */ QString DDesktopEntry::genericName() const { return localizedValue(QStringLiteral("GenericName")); } /*! @~english @brief Display name specially for DDE applications. This will check "X-Deepin-Vendor" and will return the localized string value of "GenericName" if "X-Deepin-Vendor" is "deepin", or it will return the localized string value of "Name". @return Returns the display name specially for DDE applications. @sa localizedValue(), name(), genericName() */ QString DDesktopEntry::ddeDisplayName() const { QString deepinVendor = stringValue("X-Deepin-Vendor"); QString genericNameStr = genericName(); if (deepinVendor == QStringLiteral("deepin") && !genericNameStr.isEmpty()) { return genericNameStr; } return name(); } /*! @~english @brief Returns the localized string value of the "Comment" key under "Desktop Entry" section. It's equivalent to calling localizedValue("Comment"). @return Returns the localized string value of the "Comment" key under "Desktop Entry" section. @sa localizedValue() */ QString DDesktopEntry::comment() const { return localizedValue(QStringLiteral("Comment")); } /*! @~english @brief Returns the raw string value associated with the given \a key in \a section. If the entry contains no item with the key, the function returns a constructed \a defaultValue. @return Returns the raw string value associated with the given \a key in \a section. @sa stringValue() localizedValue() stringListValue() */ QString DDesktopEntry::rawValue(const QString &key, const QString §ion, const QString &defaultValue) const { Q_D(const DDesktopEntry); QString result = defaultValue; if (key.isEmpty() || section.isEmpty()) { qWarning("DDesktopEntry::value: Empty key or section passed"); return result; } const_cast(d)->get(section, key, &result); // FIXME: better way than const_cast? return result; } /*! @~english @brief Returns the unescaped string value associated with the given \a key in \a section. If the entry contains no item with the key, the function returns a constructed \a defaultValue. @return Returns the unescaped string value associated with the given \a key in \a section. @sa rawValue() localizedValue() stringListValue() */ QString DDesktopEntry::stringValue(const QString &key, const QString §ion, const QString &defaultValue) const { QString rawResult = rawValue(key, section, defaultValue); rawResult = DDesktopEntry::unescape(rawResult); return rawResult; } /*! @~english @brief Returns the localized string value associated with the given \a key and \a localeKey in \a section. If the given \a localeKey can't be found, it will fallback to "C", if still cannot found, will fallback to the key without localeKey. If the entry contains no item with the key, the function returns a constructed \a defaultValue. @return Returns the localized string value associated with the given \a key and \a localeKey in \a section. @sa rawValue() stringValue() stringListValue() */ QString DDesktopEntry::localizedValue(const QString &key, const QString &localeKey, const QString §ion, const QString &defaultValue) const { Q_D(const DDesktopEntry); QString result = defaultValue; QString actualLocaleKey = QLatin1String("C"); if (key.isEmpty() || section.isEmpty()) { qWarning("DDesktopEntry::localizedValue: Empty key or section passed"); return result; } QStringList possibleKeys; // 此处添加 bcp47Name() 是为了兼容 desktop 文件中的语言长短名解析。 // 比如芬兰语,有 [fi] 和 [fi_FI] 两种情况,QLocale::name() 对应 fi_FI,QLocale::bcp47Name() 对应 fi。 if (!localeKey.isEmpty()) { if (localeKey == "empty") { possibleKeys << key; } else if (localeKey == "default") { possibleKeys << QString("%1[%2]").arg(key, QLocale().name()); possibleKeys << QString("%1[%2]").arg(key, QLocale().bcp47Name()); } else if (localeKey == "system") { possibleKeys << QString("%1[%2]").arg(key, QLocale::system().name()); possibleKeys << QString("%1[%2]").arg(key, QLocale::system().bcp47Name()); } else { possibleKeys << QString("%1[%2]").arg(key, localeKey); } } if (!actualLocaleKey.isEmpty()) { possibleKeys << QString("%1[%2]").arg(key, actualLocaleKey); } possibleKeys << QString("%1[%2]").arg(key, "C"); possibleKeys << key; for (const QString &oneKey : possibleKeys) { if (d->contains(section, oneKey)) { const_cast(d)->get(section, oneKey, &result); break; } } return result; } /*! @~english @brief Returns the localized string value associated with the given \a key and \a locale in \a section. If the given \a locale can't be found, it will fallback to "C", if still cannot found, will fallback to the key without a locale key. If the entry contains no item with the key, the function returns a default-constructed value. @return Returns the localized string value associated with the given \a key and \a locale in \a section. @sa rawValue() stringValue() stringListValue() */ QString DDesktopEntry::localizedValue(const QString &key, const QLocale &locale, const QString §ion, const QString &defaultValue) const { return localizedValue(key, locale.name(), section, defaultValue); } /*! @~english @brief Returns a list of strings associated with the given \a key in the given \a section. If the entry contains no item with the key, the function returns a empty string list. @return Returns a list of strings associated with the given \a key in the given \a section. @sa rawValue() stringValue() localizedValue() */ QStringList DDesktopEntry::stringListValue(const QString &key, const QString §ion) const { Q_D(const DDesktopEntry); QString value; const_cast(d)->get(section, key, &value); if (value.endsWith(';')) { value = value.left(value.length() - 1); } QStringList&& strings = value.split(';'); QString combine; QStringList result; for (QString oneStr : strings) { if (oneStr.endsWith('\\')) { combine = combine + oneStr + ';'; continue; } if (!combine.isEmpty()) { oneStr = combine + oneStr; combine.clear(); } result << DDesktopEntry::unescape(oneStr, true); } return result; } bool DDesktopEntry::setRawValue(const QString &value, const QString &key, const QString §ion) { Q_D(DDesktopEntry); if (key.isEmpty() || section.isEmpty()) { qWarning("DDesktopEntry::setRawValue: Empty key or section passed"); return false; } bool result = d->set(section, key, value); return result; } bool DDesktopEntry::setStringValue(const QString &value, const QString &key, const QString §ion) { QString escapedValue = value; DDesktopEntry::escape(escapedValue); bool result = setRawValue(escapedValue, key, section); return result; } bool DDesktopEntry::setLocalizedValue(const QString &value, const QString &localeKey, const QString &key, const QString §ion) { Q_D(DDesktopEntry); if (key.isEmpty() || section.isEmpty()) { qWarning("DDesktopEntry::setLocalizedValue: Empty key or section passed"); return false; } QString actualKey = localeKey.isEmpty() ? key : QString("%1[%2]").arg(key, localeKey); bool result = d->set(section, actualKey, value); return result; } bool DDesktopEntry::removeEntry(const QString &key, const QString §ion) { Q_D(DDesktopEntry); if (key.isEmpty() || section.isEmpty()) { qWarning("DDesktopEntry::setLocalizedValue: Empty key or section passed"); return false; } bool result = d->remove(section, key); return result; } /************************************************ The escape sequences \s, \n, \t, \r, and \\ are supported for values of type string and localestring, meaning ASCII space, newline, tab, carriage return, and backslash, respectively. ************************************************/ QString &DDesktopEntry::escape(QString &str) { QHash repl; repl.insert(QLatin1Char('\n'), QLatin1Char('n')); repl.insert(QLatin1Char('\t'), QLatin1Char('t')); repl.insert(QLatin1Char('\r'), QLatin1Char('r')); return doEscape(str, repl); } /************************************************ Quoting must be done by enclosing the argument between double quotes and escaping the double quote character, backtick character ("`"), dollar sign ("$") and backslash character ("\") by preceding it with an additional backslash character. Implementations must undo quoting before expanding field codes and before passing the argument to the executable program. Note that the general escape rule for values of type string states that the backslash character can be escaped as ("\\") as well and that this escape rule is applied before the quoting rule. As such, to unambiguously represent a literal backslash character in a quoted argument in a desktop entry file requires the use of four successive backslash characters ("\\\\"). Likewise, a literal dollar sign in a quoted argument in a desktop entry file is unambiguously represented with ("\\$"). ************************************************/ QString &DDesktopEntry::escapeExec(QString &str) { QHash repl; // The parseCombinedArgString() splits the string by the space symbols, // we temporarily replace them on the special characters. // Replacement will reverse after the splitting. repl.insert(QLatin1Char('"'), QLatin1Char('"')); // double quote, repl.insert(QLatin1Char('\''), QLatin1Char('\'')); // single quote ("'"), repl.insert(QLatin1Char('\\'), QLatin1Char('\\')); // backslash character ("\"), repl.insert(QLatin1Char('$'), QLatin1Char('$')); // dollar sign ("$"), return doEscape(str, repl); } /* The escape sequences \s, \n, \t, \r, and \\ are supported for values of type string and localestring, meaning ASCII space, newline, tab, carriage return, and backslash, respectively. Some keys can have multiple values. In such a case, the value of the key is specified as a plural: for example, string(s). The multiple values should be separated by a semicolon and the value of the key may be optionally terminated by a semicolon. Trailing empty strings must always be terminated with a semicolon. Semicolons in these values need to be escaped using \;. https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#value-types */ QString &DDesktopEntry::unescape(QString &str, bool unescapeSemicolons) { QHash repl; repl.insert(QLatin1Char('\\'), QLatin1Char('\\')); repl.insert(QLatin1Char('s'), QLatin1Char(' ')); repl.insert(QLatin1Char('n'), QLatin1Char('\n')); repl.insert(QLatin1Char('t'), QLatin1Char('\t')); repl.insert(QLatin1Char('r'), QLatin1Char('\r')); if (unescapeSemicolons) { repl.insert(QLatin1Char(';'), QLatin1Char(';')); } return doUnescape(str, repl); } /************************************************ Quoting must be done by enclosing the argument between double quotes and escaping the double quote character, backtick character ("`"), dollar sign ("$") and backslash character ("\") by preceding it with an additional backslash character. Implementations must undo quoting before expanding field codes and before passing the argument to the executable program. Reserved characters are space (" "), tab, newline, double quote, single quote ("'"), backslash character ("\"), greater-than sign (">"), less-than sign ("<"), tilde ("~"), vertical bar ("|"), ampersand ("&"), semicolon (";"), dollar sign ("$"), asterisk ("*"), question mark ("?"), hash mark ("#"), parenthesis ("(") and (")") backtick character ("`"). Note that the general escape rule for values of type string states that the backslash character can be escaped as ("\\") as well and that this escape rule is applied before the quoting rule. As such, to unambiguously represent a literal backslash character in a quoted argument in a desktop entry file requires the use of four successive backslash characters ("\\\\"). Likewise, a literal dollar sign in a quoted argument in a desktop entry file is unambiguously represented with ("\\$"). ************************************************/ QString &DDesktopEntry::unescapeExec(QString &str) { unescape(str); QHash repl; // The parseCombinedArgString() splits the string by the space symbols, // we temporarily replace them on the special characters. // Replacement will reverse after the splitting. repl.insert(QLatin1Char(' '), QChar::fromLatin1(01)); // space repl.insert(QLatin1Char('\t'), QChar::fromLatin1(02)); // tab repl.insert(QLatin1Char('\n'), QChar::fromLatin1(03)); // newline, repl.insert(QLatin1Char('"'), QLatin1Char('"')); // double quote, repl.insert(QLatin1Char('\''), QLatin1Char('\'')); // single quote ("'"), repl.insert(QLatin1Char('\\'), QLatin1Char('\\')); // backslash character ("\"), repl.insert(QLatin1Char('>'), QLatin1Char('>')); // greater-than sign (">"), repl.insert(QLatin1Char('<'), QLatin1Char('<')); // less-than sign ("<"), repl.insert(QLatin1Char('~'), QLatin1Char('~')); // tilde ("~"), repl.insert(QLatin1Char('|'), QLatin1Char('|')); // vertical bar ("|"), repl.insert(QLatin1Char('&'), QLatin1Char('&')); // ampersand ("&"), repl.insert(QLatin1Char(';'), QLatin1Char(';')); // semicolon (";"), repl.insert(QLatin1Char('$'), QLatin1Char('$')); // dollar sign ("$"), repl.insert(QLatin1Char('*'), QLatin1Char('*')); // asterisk ("*"), repl.insert(QLatin1Char('?'), QLatin1Char('?')); // question mark ("?"), repl.insert(QLatin1Char('#'), QLatin1Char('#')); // hash mark ("#"), repl.insert(QLatin1Char('('), QLatin1Char('(')); // parenthesis ("(") repl.insert(QLatin1Char(')'), QLatin1Char(')')); // parenthesis (")") repl.insert(QLatin1Char('`'), QLatin1Char('`')); // backtick character ("`"). return doUnescape(str, repl); } bool DDesktopEntry::setStatus(const DDesktopEntry::Status &status) { Q_D(DDesktopEntry); d->setStatus(status); return true; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dlicenseinfo.cpp000066400000000000000000000123761476226660600172260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dlicenseinfo.h" #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE class DLicenseInfo::DComponentInfoPrivate : public DObjectPrivate { public: QString name; QString version; QString copyRight; QString licenseName; protected: explicit DComponentInfoPrivate(DLicenseInfo::DComponentInfo *qq) : DObjectPrivate(qq) { } private: Q_DECLARE_PUBLIC(DLicenseInfo::DComponentInfo) friend class DLicenseInfoPrivate; }; DLicenseInfo::DComponentInfo::DComponentInfo(DObject * parent) : DObject(*new DLicenseInfo::DComponentInfoPrivate(this), parent) { } DLicenseInfo::DComponentInfo::~DComponentInfo() { } QString DLicenseInfo::DComponentInfo::name() const { return d_func()->name; } QString DLicenseInfo::DComponentInfo::version() const { return d_func()->version; } QString DLicenseInfo::DComponentInfo::copyRight() const { return d_func()->copyRight; } QString DLicenseInfo::DComponentInfo::licenseName() const { return d_func()->licenseName; } class Q_DECL_HIDDEN DLicenseInfoPrivate : public DObjectPrivate { public: explicit DLicenseInfoPrivate(DLicenseInfo *qq); ~DLicenseInfoPrivate() override; bool loadFile(const QString &file); bool loadContent(const QByteArray &content); QByteArray licenseContent(const QString &licenseName); void clear(); QString licenseSearchPath; DLicenseInfo::DComponentInfos componentInfos; }; DLicenseInfoPrivate::DLicenseInfoPrivate(DLicenseInfo *qq) : DObjectPrivate(qq) { } DLicenseInfoPrivate::~DLicenseInfoPrivate() { clear(); } bool DLicenseInfoPrivate::loadFile(const QString &file) { QFile jsonFile(file); if (!jsonFile.open(QIODevice::ReadOnly)) { qWarning() << QString("Failed on open file: \"%1\", error message: \"%2\"").arg( qPrintable(jsonFile.fileName()), qPrintable(jsonFile.errorString())); return false; } return loadContent(jsonFile.readAll()); } bool DLicenseInfoPrivate::loadContent(const QByteArray &content) { QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &error); if (error.error != QJsonParseError::NoError) { qWarning() << "When loading the license, parseJson failed:" << qPrintable(error.errorString()); return false; } if (!jsonDoc.isArray()) { qWarning() << "When loading the license, parseJson failed: it is not a JSON array"; return false; } clear(); QJsonArray array = jsonDoc.array(); for (const QJsonValue &value : array) { if (!value.isObject()) { qWarning() << "When loading the license, parseJson failed: it is not a JSON object!"; return false; } DLicenseInfo::DComponentInfo *componentInfo = new DLicenseInfo::DComponentInfo; QJsonObject obj = value.toObject(); QJsonValue name = obj.value("name"); QJsonValue version = obj.value("version"); QJsonValue copyright = obj.value("copyright"); QJsonValue license = obj.value("license"); if (!name.isString() || !version.isString() || !copyright.isString() || !license.isString()) { qWarning() << "When loading the license, parseJson failed: it is not a string!"; return false; } componentInfo->d_func()->name = name.toString(); componentInfo->d_func()->version = version.toString(); componentInfo->d_func()->copyRight = copyright.toString(); componentInfo->d_func()->licenseName = license.toString(); componentInfos.append(componentInfo); } return true; } QByteArray DLicenseInfoPrivate::licenseContent(const QString &licenseName) { QByteArray content; QStringList dirs{"/usr/share/spdx-license"}; if (!licenseSearchPath.isEmpty()) dirs.prepend(licenseSearchPath); for (const QString &dir : dirs) { QFile file(QString("%1/%2.txt").arg(dir).arg(licenseName)); if (!file.exists()) continue; if (file.open(QIODevice::ReadOnly)) { content = file.readAll(); file.close(); break; } } if (content.isEmpty()) { qWarning() << QString("License content is empty when getting license content!"); } return content; } void DLicenseInfoPrivate::clear() { qDeleteAll(componentInfos); componentInfos.clear(); } DLicenseInfo::DLicenseInfo(DObject *parent) : DObject(*new DLicenseInfoPrivate(this), parent) { } bool DLicenseInfo::loadContent(const QByteArray &content) { D_D(DLicenseInfo); return d->loadContent(content); } bool DLicenseInfo::loadFile(const QString &file) { D_D(DLicenseInfo); return d->loadFile(file); } void DLicenseInfo::setLicenseSearchPath(const QString &path) { D_D(DLicenseInfo); d->licenseSearchPath = path; } QByteArray DLicenseInfo::licenseContent(const QString &licenseName) { D_D(DLicenseInfo); return d->licenseContent(licenseName); } DLicenseInfo::DComponentInfos DLicenseInfo::componentInfos() const { D_DC(DLicenseInfo); return d->componentInfos; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dsecurestring.cpp000066400000000000000000000006101476226660600174310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsecurestring.h" #include "dutil.h" #include DCORE_BEGIN_NAMESPACE DSecureString::DSecureString(const QString &other) noexcept : QString(other) { } DSecureString::~DSecureString() { DUtil::SecureErase(*this); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dsgapplication.cpp000066400000000000000000000076521476226660600175660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsgapplication.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef QT_DEBUG Q_LOGGING_CATEGORY(dsgApp, "dtk.core.dsg") #else Q_LOGGING_CATEGORY(dsgApp, "dtk.core.dsg", QtInfoMsg) #endif DCORE_BEGIN_NAMESPACE static inline QByteArray getSelfAppId() { // The env is set by the application starter(eg, org.desktopspec.ApplicationManager service) QByteArray selfId = qgetenv("DSG_APP_ID"); if (!selfId.isEmpty()) return selfId; return DSGApplication::getId(QCoreApplication::applicationPid()); } static bool isServiceActivatable(const QString &service) { if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(service)) return false; const QDBusReply activatableNames = QDBusConnection::sessionBus().interface()-> callWithArgumentList(QDBus::AutoDetect, QLatin1String("ListActivatableNames"), QList()); return activatableNames.value().contains(service); } // Format appId to valid. static QByteArray formatAppId(const QByteArray &appId) { static const QRegularExpression regex("[^\\w\\-\\.]"); QString format(appId); format.replace(QDir::separator(), "."); format = format.replace(regex, QStringLiteral("-")); const QString InvalidPrefix{"."}; if (format.startsWith(InvalidPrefix)) format = format.mid(InvalidPrefix.size()); return format.toLocal8Bit(); } QByteArray DSGApplication::id() { static QByteArray selfId = getSelfAppId(); if (!selfId.isEmpty()) return selfId; QByteArray result = selfId; if (!qEnvironmentVariableIsSet("DTK_DISABLED_FALLBACK_APPID")) { result = QCoreApplication::applicationName().toLocal8Bit(); if (result.isEmpty()) { QFile file("/proc/self/cmdline"); if (file.open(QIODevice::ReadOnly)) result = file.readLine(); } if (result.isEmpty()) { const QFileInfo file(QFile::symLinkTarget("/proc/self/exe")); if (file.exists()) result = file.absoluteFilePath().toLocal8Bit(); } if (!result.isEmpty()) { result = formatAppId(result); qCDebug(dsgApp) << "The applicatiion ID is fallback to " << result; } } if (result.isEmpty()) qCWarning(dsgApp) << "The application ID is empty."; return result; } QByteArray DSGApplication::getId(qint64 pid) { if (!isServiceActivatable("org.desktopspec.ApplicationManager1")) { qCInfo(dsgApp) << "Can't getId from AM for the " << pid << ", because AM is unavailable."; return QByteArray(); } int pidfd = syscall(SYS_pidfd_open, pid, 0); if (pidfd < 0) { qCWarning(dsgApp) << "pidfd open failed:" << strerror(errno) << ", the pid:" << pid; return QByteArray(); } DDBusInterface infc("org.desktopspec.ApplicationManager1", "/org/desktopspec/ApplicationManager1", "org.desktopspec.ApplicationManager1"); QDBusReply reply = infc.call("Identify", QVariant::fromValue(QDBusUnixFileDescriptor(pidfd))); // see QDBusUnixFileDescriptor: The original file descriptor is not touched and must be closed by the user. close(pidfd); if (!reply.isValid()) { qCWarning(dsgApp) << "Identify from AM failed." << reply.error().message(); return QByteArray(); } const QByteArray appId = reply.value().toLatin1(); qCInfo(dsgApp) << "AppId is fetched from AM, and value is " << appId; return appId; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dsysinfo.cpp000066400000000000000000001151721476226660600164200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsysinfo.h" #include "ddesktopentry.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_LINUX #include #include #include #endif #define OS_VERSION_FILE DSYSINFO_PREFIX"/etc/os-version" #define LSB_RELEASE_FILE DSYSINFO_PREFIX"/etc/lsb-release" #define OS_RELEASE_FILE DSYSINFO_PREFIX"/etc/os-release" #define DEEPIN_VERSION_FILE DSYSINFO_PREFIX"/etc/deepin-version" static inline bool inTest() { return !QLatin1String(DSYSINFO_PREFIX).isEmpty(); } DCORE_BEGIN_NAMESPACE #ifdef QT_DEBUG Q_LOGGING_CATEGORY(logSysInfo, "dtk.dsysinfo") #else Q_LOGGING_CATEGORY(logSysInfo, "dtk.dsysinfo", QtInfoMsg) #endif class Q_DECL_HIDDEN DSysInfoPrivate { public: DSysInfoPrivate(); #ifdef Q_OS_LINUX void ensureDeepinInfo(); bool ensureOsVersion(); void ensureDistributionInfo(); bool splitA_BC_DMode(); #endif void ensureReleaseInfo(); void ensureComputerInfo(); QMap parseInfoFile(QFile &file); QMap parseInfoContent(const QString &content); #ifdef Q_OS_LINUX DSysInfo::DeepinType deepinType = DSysInfo::DeepinType(-1); QMap deepinTypeMap; //Type Name with Language QString deepinVersion; QString deepinEdition; QString deepinCopyright; QString majorVersion; QString minorVersion; struct MinVersion { enum Type { A_BC_D, /*!< Professional Edition*/ X_Y_Z, /*!< Home Edition*/ A_B_C /*!< Community Edition*/ }; MinVersion() : A(0) , B(0) , BC(0) , C(0) , D(0) , X(0) , Y(0) , Z(0) { } uint A, B, BC, C, D; // A-BC-D uint X, Y, Z; Type type; }; struct OSBuild { OSBuild():A(0), B(0), C(0), D(0), xyz(100){ } uint A, B, C, D, E, xyz; // ABCDE.xyz }; MinVersion minVersion; OSBuild osBuild; #endif QScopedPointer distributionInfo; DSysInfo::ProductType productType = DSysInfo::ProductType(-1); QString prettyName; QString productTypeString; QString productVersion; QString computerName; QString cpuModelName; qint64 memoryAvailableSize = -1; qint64 memoryInstalledSize = -1; qint64 diskSize = 0; }; DSysInfoPrivate::DSysInfoPrivate() { } #ifdef Q_OS_LINUX void DSysInfoPrivate::ensureDistributionInfo() { if (distributionInfo) return; const QString distributionInfoFile(DSysInfo::distributionInfoPath()); // Generic DDE distribution info distributionInfo.reset(new DDesktopEntry(distributionInfoFile)); } bool DSysInfoPrivate::splitA_BC_DMode() { // A-BC-D bool ok = false; uint minv = minorVersion.toUInt(&ok); if (ok) { minVersion.D = minv % 10; } else if (minorVersion.length() > 0) { const QString D = minorVersion.right(1); if (D.contains(QRegularExpression("[0-9A-Z]"))) { // 0-9...A-Z minVersion.D = 10 + static_cast(D.data()->toLatin1() - 'A'); } else { qWarning() << "invalid minorVersion"; minVersion.D = 0; } } uint minVer = minorVersion.left(3).toUInt(); minVersion.BC = minVer % 100; minVer /= 100; minVersion.A = minVer % 10; minVersion.type = MinVersion::A_BC_D; return ok; } void DSysInfoPrivate::ensureDeepinInfo() { if (static_cast(deepinType) > 0 && !inTest()) return; if (inTest()) deepinTypeMap.clear(); // clear cache for test QFile file(DEEPIN_VERSION_FILE); if (!file.open(QFile::ReadOnly)) { deepinType = DSysInfo::UnknownDeepin; return; } char buf[1024]; int buf_length = 0; Q_FOREVER { buf_length = file.readLine(buf, sizeof(buf)); if (buf_length < 0) break; const QByteArray line(buf, buf_length); const QByteArrayList &list = line.split('='); if (list.count() != 2) { continue; } const auto key_value = qMakePair(list.first().trimmed(), list.last().trimmed()); if (key_value.first == "Version") { deepinVersion = key_value.second; } else if (line.startsWith("Type")) { if (key_value.first == "Type") { deepinTypeMap[QString()] = QString::fromLatin1(key_value.second); } else if (key_value.first.at(4) == '[' && key_value.first.at(key_value.first.size() - 1) == ']') { const QByteArray &language = key_value.first.mid(5, key_value.first.size() - 6); if (!language.isEmpty()) { deepinTypeMap[QString::fromLatin1(language)] = QString::fromUtf8(key_value.second); } } } else if (key_value.first == "Edition") { deepinEdition = QString::fromUtf8(key_value.second); } else if (key_value.first == "Copyright") { deepinCopyright = QString::fromUtf8(key_value.second); } // deepinTypeMap may not parse finished(multi language) but !deepinTypeMap.isEmpty() // if (!deepinTypeMap.isEmpty() && !deepinEdition.isEmpty() && !deepinCopyright.isEmpty()) { // break; // } } file.close(); const QString &deepin_type = deepinTypeMap[QString()]; if (deepin_type.isEmpty()) { deepinType = DSysInfo::UnknownDeepin; } else if (deepin_type == "Desktop") { deepinType = DSysInfo::DeepinDesktop; } else if (deepin_type == "Professional") { deepinType = DSysInfo::DeepinProfessional; } else if (deepin_type == "Server") { deepinType = DSysInfo::DeepinServer; } else if (deepin_type == "Personal") { deepinType = DSysInfo::DeepinPersonal; } else if (deepin_type == "Military") { deepinType = DSysInfo::DeepinMilitary; } else { deepinType = DSysInfo::UnknownDeepin; } } bool DSysInfoPrivate::ensureOsVersion() { if (osBuild.A > 0 && !inTest()) return true; DDesktopEntry entry(OS_VERSION_FILE); bool ok = false; #define D_ASSET_EXIT(con, msg) do { \ if (!(con)) { \ qWarning() << __func__ << msg; \ return false; \ } \ } while (false) D_ASSET_EXIT(entry.status() == DDesktopEntry::NoError, entry.status()); // 先获取版本信息 // ABCDE.xyz.abc QString osb = entry.stringValue("OsBuild", "Version"); QStringList osbs = osb.split("."); ok = (osbs.size() >= 2 && osbs.value(0).size() == 5); D_ASSET_EXIT(ok, "OsBuild version invalid!"); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) const QStringList &left = osbs.value(0).split(QString(), Qt::SkipEmptyParts); #else const QStringList &left = osbs.value(0).split(QString(), QString::SkipEmptyParts); #endif D_ASSET_EXIT(left.size() == 5, "OsBuild version(ls) invalid!"); int idx = 0; osBuild.A = left.value(idx++, "0").toUInt(&ok); D_ASSET_EXIT(ok, "OsBuild version(A) invalid!"); osBuild.B = left.value(idx++, "0").toUInt(&ok); D_ASSET_EXIT(ok, "OsBuild version(B) invalid!"); osBuild.C = left.value(idx++, "0").toUInt(&ok); if (!ok) { auto c = left.value(idx-1, "0").toLatin1(); D_ASSET_EXIT(c.size()>0, "OsBuild version(C) invalid!"); osBuild.C = uint(c.at(0)); } osBuild.D = left.value(idx++, "0").toUInt(&ok); D_ASSET_EXIT(ok, "OsBuild version(D) invalid!"); osBuild.E = left.value(idx++, "0").toUInt(&ok); D_ASSET_EXIT(ok, "OsBuild version(E) invalid!"); // xyz osBuild.xyz = osbs.value(1).trimmed().toUInt(&ok); majorVersion = entry.stringValue("MajorVersion", "Version"); minorVersion = entry.stringValue("MinorVersion", "Version"); switch (osBuild.D) { case 7: { // Home Edition uses the form of "full version number coding -x.y.z" const QStringList &versionList = minorVersion.split('.'); if (versionList.isEmpty()) { // If the reading fails, return it directly to empty qWarning() << "no minorVersion"; return false; } else if (versionList.length() == 2) { // Z is 0 minVersion.X = versionList.first().toUInt(); minVersion.Y = versionList.last().toUInt(); minVersion.Z = 0; } else if (versionList.length() == 3) { // X.Y.Z exists minVersion.X = versionList.at(0).toUInt(); minVersion.Y = versionList.at(1).toUInt(); minVersion.Z = versionList.at(2).toUInt(); } minVersion.type = MinVersion::X_Y_Z; } break; case 3: { // The community version uses the form of "full version number coding A.B.C" bool a_bc_dMode = false; const QStringList &versionList = minorVersion.split('.'); if (versionList.isEmpty()) { // If the reading fails, return it directly to empty qWarning() << "no minorVersion"; return false; } else if (versionList.length() == 1) { QString modeVersion = versionList.first(); if (modeVersion.length() == 2) { //A.B.C mode and B c are 0 minVersion.A = modeVersion.toUInt(); minVersion.B = 0; minVersion.C = 0; } else { // A_BC_D mode splitA_BC_DMode(); a_bc_dMode = true; } } else if (versionList.length() == 2) { // C=0 minVersion.A = versionList.first().toUInt(); minVersion.B = versionList.last().toUInt(); minVersion.C = 0; } else if (versionList.length() == 3) { // A.B.C exists minVersion.A = versionList.at(0).toUInt(); minVersion.B = versionList.at(1).toUInt(); minVersion.C = versionList.at(2).toUInt(); } if (!a_bc_dMode) minVersion.type = MinVersion::A_B_C; } break; default: { // A-BC-D ok = splitA_BC_DMode(); } break; } return ok; } static QString unquote(const QByteArray &value) { if (value.at(0) == '"' || value.at(0) == '\'') { return QString::fromLatin1(value.mid(1, value.size() - 2)); } return QString::fromLatin1(value); } static bool readEtcFile(DSysInfoPrivate *info, const char *filename, const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey) { QFile file(QString::fromLatin1(filename)); if (!file.open(QIODevice::ReadOnly)) { return false; } quint8 valid_data_count = 0; char buf[1024]; if (inTest()) { // for test clear cache info->productTypeString.clear(); info->productType = DSysInfo::UnknownType; } while (valid_data_count < 3) { int buf_length = file.readLine(buf, sizeof(buf)); if (buf_length < 0) break; const QByteArray line(buf, buf_length - 1); if (info->productTypeString.isEmpty() && line.startsWith(idKey)) { const QByteArray value(line.constData() + idKey.size()); info->productTypeString = unquote(value); ++valid_data_count; continue; } if (info->prettyName.isEmpty() && line.startsWith(prettyNameKey)) { const QByteArray value(line.constData() + prettyNameKey.size()); info->prettyName = unquote(value); ++valid_data_count; continue; } if (info->productVersion.isEmpty() && line.startsWith(versionKey)) { const QByteArray value(line.constData() + versionKey.size()); info->productVersion = unquote(value); ++valid_data_count; continue; } } file.close(); return valid_data_count != 0; } static bool readOsRelease(DSysInfoPrivate *info) { if (!readEtcFile(info, OS_RELEASE_FILE, "ID=", "VERSION_ID=", "PRETTY_NAME=")) return readEtcFile(info, DSYSINFO_PREFIX"/usr/lib/os-release", "ID=", "VERSION_ID=", "PRETTY_NAME="); return true; } static bool readLsbRelease(DSysInfoPrivate *info) { return readEtcFile(info, LSB_RELEASE_FILE, "DISTRIB_ID=", "DISTRIB_RELEASE=", "DISTRIB_DESCRIPTION="); } #endif void DSysInfoPrivate::ensureReleaseInfo() { if (productType > 0 && !inTest()) { return; } #ifdef Q_OS_LINUX readOsRelease(this); readLsbRelease(this); if (productTypeString.isEmpty()) { productType = DSysInfo::UnknownType; } else { switch (productTypeString.at(0).unicode()) { case 'd': case 'D': if (productTypeString.compare("deepin", Qt::CaseInsensitive) == 0) { productType = DSysInfo::Deepin; } else if (productTypeString.compare("debian", Qt::CaseInsensitive) == 0) { productType = DSysInfo::Debian; } break; case 'a': case 'A': if (productTypeString.compare("arch", Qt::CaseInsensitive) == 0) productType = DSysInfo::ArchLinux; break; case 'c': case 'C': if (productTypeString.compare("centos", Qt::CaseInsensitive) == 0) productType = DSysInfo::CentOS; break; case 'f': case 'F': if (productTypeString.compare("fedora", Qt::CaseInsensitive) == 0) productType = DSysInfo::Fedora; break; case 'g': case 'G': if (productTypeString.compare("gentoo", Qt::CaseInsensitive) == 0) productType = DSysInfo::Gentoo; break; case 'l': case 'L': if (productTypeString.compare("linuxmint", Qt::CaseInsensitive) == 0) productType = DSysInfo::LinuxMint; break; case 'm': case 'M': if (productTypeString.compare("manjaro", Qt::CaseInsensitive) == 0) productType = DSysInfo::Manjaro; break; case 'n': case 'N': if (productTypeString.compare("nixos", Qt::CaseInsensitive) == 0) productType = DSysInfo::NixOS; break; case 'o': case 'O': if (productTypeString.compare("opensuse", Qt::CaseInsensitive) == 0) productType = DSysInfo::openSUSE; break; case 's': case 'S': if (productTypeString.compare("sailfishos", Qt::CaseInsensitive) == 0) productType = DSysInfo::SailfishOS; break; case 'u': case 'U': if (productTypeString.compare("ubuntu", Qt::CaseInsensitive) == 0) { productType = DSysInfo::Ubuntu; } else if (productTypeString.compare("uos", Qt::CaseInsensitive) == 0 || productTypeString.compare("UnionTech OS", Qt::CaseInsensitive) == 0) { productType = DSysInfo::Uos; } break; default: productType = DSysInfo::UnknownType; break; } } #endif } void DSysInfoPrivate::ensureComputerInfo() { #ifdef Q_OS_LINUX #endif } QMap DSysInfoPrivate::parseInfoFile(QFile &file) { char buf[1024]; qint64 lineLength = 0; QMap map; do { lineLength = file.readLine(buf, sizeof(buf)); QString s(buf); if (s.contains(':')) { QStringList list = s.split(':'); if (list.size() == 2) { map.insert(list.first().trimmed(), list.back().trimmed()); } } } while (lineLength >= 0); return map; } QMap DSysInfoPrivate::parseInfoContent(const QString &content) { QMap map; QStringList lineContents = content.split("\n"); for (auto lineContent : lineContents) { if (lineContent.contains(':')) { QStringList list = lineContent.split(':'); if (list.size() == 2) { map.insert(list.first().trimmed(), list.back().trimmed()); } } } return map; } Q_GLOBAL_STATIC(DSysInfoPrivate, siGlobal) QString DSysInfo::operatingSystemName() { siGlobal->ensureReleaseInfo(); return siGlobal->prettyName; } #ifdef Q_OS_LINUX /*! \brief Check current distro is Deepin or not. \note Uos will also return true. */ bool DSysInfo::isDeepin() { siGlobal->ensureReleaseInfo(); return productType() == Deepin || productType() == Uos; } bool DSysInfo::isDDE() { if (!DSysInfo::isDeepin()) { const QByteArray &xsd = qgetenv("XDG_SESSION_DESKTOP"); return !xsd.compare("deepin", Qt::CaseInsensitive) || !xsd.compare("DDE", Qt::CaseInsensitive); } siGlobal->ensureDeepinInfo(); return siGlobal->deepinType != UnknownDeepin; } DSysInfo::DeepinType DSysInfo::deepinType() { siGlobal->ensureDeepinInfo(); return siGlobal->deepinType; } QString DSysInfo::deepinTypeDisplayName(const QLocale &locale) { siGlobal->ensureDeepinInfo(); return siGlobal->deepinTypeMap.value(locale.name(), siGlobal->deepinTypeMap.value(QString())); } QString DSysInfo::deepinVersion() { siGlobal->ensureDeepinInfo(); return siGlobal->deepinVersion; } QString DSysInfo::deepinEdition() { siGlobal->ensureDeepinInfo(); return siGlobal->deepinEdition; } QString DSysInfo::deepinCopyright() { siGlobal->ensureDeepinInfo(); return siGlobal->deepinCopyright; } /*! @~english \brief Display system type [1: desktop] [2: server] [3: special devices] \note 根据 osBuild.B 判断 */ DSysInfo::UosType DSysInfo::uosType() { if (!DSysInfo::isDeepin() && !inTest()) return UosTypeUnknown; siGlobal->ensureOsVersion(); UosType ost = UosTypeUnknown; if ((siGlobal->osBuild.B > UosTypeUnknown && siGlobal->osBuild.B < UosTypeCount)) { ost = static_cast(siGlobal->osBuild.B); } return ost; } /*! @~english \brief Editions: professional version/personal version/community version ... \note According to osbuild.b && osbuild.d */ DSysInfo::UosEdition DSysInfo::uosEditionType() { siGlobal->ensureOsVersion(); UosEdition ospt = UosEditionUnknown; if (siGlobal->osBuild.B == UosDesktop) { switch (siGlobal->osBuild.D) { case 1: return UosProfessional; case 2: case 7: //The new version of the family version (7) and the old version of the personal version (2) The same as the home does not modify the old logic (7) to ensure the adaptation of the old version return UosHome; case 3: return UosCommunity; case 4: return UosMilitary; case 5: return UosDeviceEdition; case 6: return UosEducation; default: break; } } else if (siGlobal->osBuild.B == UosServer) { switch (siGlobal->osBuild.D) { case 1: return UosEnterprise; case 2: return UosEnterpriseC; case 3: return UosEuler; case 4: return UosMilitaryS; case 5: return UosDeviceEdition; default: break; } } else if (siGlobal->osBuild.B == UosDevice){ ospt = UosEnterprise; // os-version 1.4 if B==Device then et=Enterprise } return ospt; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! @~english \brief Architecture information (using bit flags of a byte) 【0x8 sw64】【0x4 mips64】【0x2 arm64】【0x1 amd64】 */ DSysInfo::UosArch DSysInfo::uosArch() { siGlobal->ensureOsVersion(); return static_cast(siGlobal->osBuild.E); } #endif static QString getUosVersionValue(const QString &key, const QLocale &locale) { DDesktopEntry entry(OS_VERSION_FILE); QString localKey = QString("%1[%2]").arg(key, locale.name()); return entry.stringValue(localKey, "Version", entry.stringValue(key, "Version")); } /*! @~english \brief Version name ProductType[xx] The corresponding value of the item, if you can't find the value of the corresponding language, use the value of the productType (desktop/server/device) \a locale Current system language */ QString DSysInfo::uosProductTypeName(const QLocale &locale) { return getUosVersionValue("ProductType", locale); } /*! @~english \brief DSysInfo::osSystemName Version name The corresponding value corresponding to SystemName [xx] item, if you can't find the default language of the corresponding language, use the value of SystemName uniontech os \a locale Current system language */ QString DSysInfo::uosSystemName(const QLocale &locale) { return getUosVersionValue("SystemName", locale); } /*! @~english \brief DSysInfo::osEditionName Version name EditionName[xx] The corresponding value of the item, if you can't find the value of the corresponding language, use the value of EditionName (Professional/Home/Community ...) \a locale Current system language */ QString DSysInfo::uosEditionName(const QLocale &locale) { return getUosVersionValue("EditionName", locale); } /*! @~english \brief DSysInfo::spVersion Period version name BC, A.B.C in the small version number a-bc-d Return to SP1-SPXX, if the official version returns empty In the x.y.z mode, it will not support returning this version number for the time being \ note minversion.bc == 00: The official version minversion.bc | minversion.b == 01-99: SP1 ... .sp99 */ QString DSysInfo::spVersion() { siGlobal->ensureOsVersion(); switch (siGlobal->minVersion.type) { case DSysInfoPrivate::MinVersion::A_BC_D: { if (siGlobal->minVersion.BC > 0) { return QString("SP%1").arg(siGlobal->minVersion.BC); } else { return QString(); // 00 正式版 } } case DSysInfoPrivate::MinVersion::A_B_C: { if (siGlobal->minVersion.B > 0) { return QStringLiteral("SP%1").arg(siGlobal->minVersion.B); } else { return {}; } } case DSysInfoPrivate::MinVersion::X_Y_Z: qWarning() << "Getting the SP version in this mode is not supported."; return {}; } return QString(); } /*! @~english \brief DSysInfo::udpateVersion Update version name minor version number D in A-BC-D mode、C in A.B.C mode Return to Update1 ... Update9, if the official version returns to empty In the x.y.z mode, it will not support returning this version number for the time being \note minVersion.D == 0:official version minVersion.D | minVersion.C == 1-9:update1… update9,updateA...updateZ */ QString DSysInfo::udpateVersion() { siGlobal->ensureOsVersion(); switch (siGlobal->minVersion.type) { case DSysInfoPrivate::MinVersion::A_BC_D: { if (siGlobal->minVersion.D > 0) { uint uv = siGlobal->minVersion.D; if (uv < 10) { return QString("update%1").arg(uv); } else if (uv < 36) { return QString("update").append(QChar(uv - 10 + 'A')); } else { qWarning() << "invalid update versoin"; break; } } else { break; // 0 正式版 } } case DSysInfoPrivate::MinVersion::A_B_C: { if (siGlobal->minVersion.C > 0) { return QStringLiteral("update%1").arg(siGlobal->minVersion.C); } else { break; } } case DSysInfoPrivate::MinVersion::X_Y_Z: qWarning() << "Getting the update version in this mode is not supported."; break; } return {}; } /*! @~english \brief Main edition number Main edition number 【20】【23】【25】【26】【29】【30】 \note Return to Majorversion value */ QString DSysInfo::majorVersion() { siGlobal->ensureOsVersion(); return siGlobal->majorVersion; } /*! @~english \brief DSysInfo::minorVersion minor version *【ABCD】 ·[0-9]{4} *【A.B.C】 or【X.Y.Z】 @return the value of minorversion */ QString DSysInfo::minorVersion() { siGlobal->ensureOsVersion(); return siGlobal->minorVersion; } /*! @~english \brief DSysInfo::buildVersion Small version number System mirror batch number, in order of time (non-retreat) increase from 100-999 \note Return osbuild.xyz value */ QString DSysInfo::buildVersion() { DDesktopEntry entry(OS_VERSION_FILE); QString osb = entry.stringValue("OsBuild", "Version"); return osb.mid(6).trimmed(); } #endif #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DSysInfo::deepinDistributionInfoPath() { return distributionInfoPath(); } #endif QString DSysInfo::distributionInfoPath() { #ifdef Q_OS_LINUX // return "/usr/share/deepin/distribution.info"; return QStandardPaths::locate(QStandardPaths::GenericDataLocation, "deepin/distribution.info"); #else return QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)).filePath("deepin-distribution.info"); #endif // Q_OS_LINUX } QString DSysInfo::distributionInfoSectionName(DSysInfo::OrgType type) { switch (type) { case Distribution: return "Distribution"; case Distributor: return "Distributor"; case Manufacturer: return "Manufacturer"; } return QString(); } /*! @~english \return the organization name. use \a type as Distribution to get the name of current deepin distribution itself. \sa deepinDistributionInfoPath() */ QString DSysInfo::distributionOrgName(DSysInfo::OrgType type, const QLocale &locale) { #ifdef Q_OS_LINUX siGlobal->ensureDistributionInfo(); #endif QString fallback = type == Distribution ? QStringLiteral("Deepin") : QString(); return siGlobal->distributionInfo->localizedValue("Name", locale, distributionInfoSectionName(type), fallback); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DSysInfo::deepinDistributorName() { return distributionOrgName(Distributor); } #endif /*! @~english \return the organization website name and url. use \a type as Distribution to get the name of current deepin distribution itself. \sa deepinDistributionInfoPath() */ QPair DSysInfo::distributionOrgWebsite(DSysInfo::OrgType type) { #ifdef Q_OS_LINUX siGlobal->ensureDistributionInfo(); #endif QString fallbackSiteName = type == Distribution ? QStringLiteral("www.deepin.org") : QString(); QString fallbackSiteUrl = type == Distribution ? QStringLiteral("https://www.deepin.org") : QString(); return { siGlobal->distributionInfo->stringValue("WebsiteName", distributionInfoSectionName(type), fallbackSiteName), siGlobal->distributionInfo->stringValue("Website", distributionInfoSectionName(type), fallbackSiteUrl), }; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QPair DSysInfo::deepinDistributorWebsite() { return distributionOrgWebsite(Distributor); } #endif /*! @~english \return the obtained organization logo path, or the given \a fallback one if there are no such logo. use \a type as Distribution to get the logo of current deepin distribution itself. \sa deepinDistributionInfoPath() */ QString DSysInfo::distributionOrgLogo(DSysInfo::OrgType orgType, DSysInfo::LogoType type, const QString &fallback) { DDesktopEntry distributionInfo(distributionInfoPath()); QString orgSectionName = distributionInfoSectionName(orgType); switch (type) { case Normal: return distributionInfo.stringValue("Logo", orgSectionName, fallback); case Light: return distributionInfo.stringValue("LogoLight", orgSectionName, fallback); case Symbolic: return distributionInfo.stringValue("LogoSymbolic", orgSectionName, fallback); case Transparent: return distributionInfo.stringValue("LogoTransparent", orgSectionName, fallback); } return QString(); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DSysInfo::deepinDistributorLogo(DSysInfo::LogoType type, const QString &fallback) { return distributionOrgLogo(Distributor, type, fallback); } #endif DSysInfo::ProductType DSysInfo::productType() { siGlobal->ensureReleaseInfo(); return siGlobal->productType; } QString DSysInfo::productTypeString() { siGlobal->ensureReleaseInfo(); return siGlobal->productTypeString; } QString DSysInfo::productVersion() { siGlobal->ensureReleaseInfo(); return siGlobal->productVersion; } /*! @~english \brief Check if current edition is a community edition Developer can use this way to check if we need enable or disable features for community or enterprise edition. Current rule: - Professional, Server, Personal edition (DeepinType) will be treat as Enterprise edition. - Uos (ProductType) will be treat as Enterprise edition. \return true if it's on a community edition distro/installation */ bool DSysInfo::isCommunityEdition() { #ifdef Q_OS_LINUX DeepinType type = deepinType(); QList enterpriseTypes { DeepinProfessional, DeepinServer, DeepinPersonal }; if (enterpriseTypes.contains(type)) { return false; } if (productType() == Uos) { return false; } #endif // Q_OS_LINUX return true; } QString DSysInfo::computerName() { #ifdef Q_OS_LINUX struct utsname u; if (uname(&u) == 0) siGlobal->computerName = QString::fromLatin1(u.nodename); return siGlobal->computerName; #endif return QString(); } QString DSysInfo::cpuModelName() { if (!siGlobal->cpuModelName.isEmpty()) return siGlobal->cpuModelName; #ifdef Q_OS_LINUX static QFile file("/proc/cpuinfo"); if (file.open(QFile::ReadOnly)) { QMap map = siGlobal->parseInfoFile(file); if (map.contains("Processor")) { // arm-cpuinfo hw_kirin-cpuinfo siGlobal->cpuModelName = map.value("Processor"); } else if (map.contains("model name")) { // cpuinfo siGlobal->cpuModelName = map.value("model name"); } else if (map.contains("cpu model")) { // loonson3-cpuinfo sw-cpuinfo siGlobal->cpuModelName = map.value("cpu model"); } else if (map.contains("Hardware")) { // "HardWare" field contains cpu info on huawei kirin machine (e.g. klv or klu) siGlobal->cpuModelName = map.value("Hardware"); } file.close(); } // Get the cpu info by executing lscpu command if (siGlobal->cpuModelName.isEmpty()) { const auto &lscpu_command = QStandardPaths::findExecutable("lscpu"); if (lscpu_command.isEmpty()) { qWarning() << "lscpu not found"; return QString(); } QProcess lscpu; QStringList env = QProcess::systemEnvironment(); env << "LC_ALL=C"; // Add an environment variable lscpu.setEnvironment(env); lscpu.setProgram(lscpu_command); lscpu.start(); if (lscpu.waitForFinished(3000)) { const QMap map = siGlobal->parseInfoContent(lscpu.readAll()); if (map.contains("Model name")) { siGlobal->cpuModelName = map.value("Model name"); } } else { qWarning() << "lscpu:" << lscpu.errorString(); } } return siGlobal->cpuModelName; #endif return QString(); } /*! @~english \return the installed memory size */ qint64 DSysInfo::memoryInstalledSize() { #ifdef Q_OS_LINUX // Getting Memory Installed Size // TODO: way to not dept on lshw? if (siGlobal->memoryInstalledSize >= 0) { return siGlobal->memoryInstalledSize; } if (!QStandardPaths::findExecutable("lshw").isEmpty()) { QProcess lshw; lshw.start("lshw", {"-c", "memory", "-json", "-sanitize"}, QIODevice::ReadOnly); if (!lshw.waitForFinished()) { return -1; } const QByteArray &lshwInfoJson = lshw.readAllStandardOutput(); QJsonParseError error; auto doc = QJsonDocument::fromJson(lshwInfoJson, &error); if (error.error != QJsonParseError::NoError) { qCWarning(logSysInfo(), "parse failed, expect json doc from lshw command"); return -1; } if (!doc.isArray()) { qCWarning(logSysInfo(), "parse failed, expect array"); return -1; } QJsonArray lshwResultArray = doc.array(); for (const QJsonValue value : lshwResultArray) { QJsonObject obj = value.toObject(); if (obj.contains("id") && obj.value("id").toString() == "memory") { siGlobal->memoryInstalledSize = obj.value("size").toDouble(); // TODO: check "units" is "bytes" ? break; } } } Q_ASSERT(siGlobal->memoryInstalledSize > 0); return siGlobal->memoryInstalledSize; #else return -1; #endif } /*! @~english \return the total available to use memory size */ qint64 DSysInfo::memoryTotalSize() { #ifdef Q_OS_LINUX siGlobal->memoryAvailableSize = get_phys_pages() * sysconf(_SC_PAGESIZE); return siGlobal->memoryAvailableSize; #endif return -1; } qint64 DSysInfo::systemDiskSize() { #ifdef Q_OS_LINUX // Getting Disk Size QString deviceName; QProcess lsblk; lsblk.start("lsblk", {"-Jlpb", "-oNAME,KNAME,PKNAME,SIZE,MOUNTPOINT"}, QIODevice::ReadOnly); if (!lsblk.waitForFinished()) { return -1; } const QByteArray &diskStatusJson = lsblk.readAllStandardOutput(); QJsonDocument diskStatus = QJsonDocument::fromJson(diskStatusJson); QJsonValue diskStatusJsonValue = diskStatus.object().value("blockdevices"); QMap> deviceParentAndSizeMap; if (!diskStatusJsonValue.isUndefined()) { QJsonArray diskStatusArray = diskStatusJsonValue.toArray(); QString keyName; for (const QJsonValue oneValue : diskStatusArray) { QString name = oneValue.toObject().value("name").toString(); QString kname = oneValue.toObject().value("kname").toString(); QString pkname = oneValue.toObject().value("pkname").toString(); qulonglong size = oneValue.toObject().value("size").toVariant().toULongLong(); QString deviceNameMP = oneValue.toObject().value("mountpoint").toString(); if ("/" == deviceNameMP){ deviceName = name; } if (keyName.isNull() && deviceName == name) { keyName = kname; } deviceParentAndSizeMap[kname] = QPair(pkname, size); } while (!deviceParentAndSizeMap[keyName].first.isNull()) { keyName = deviceParentAndSizeMap[keyName].first; } siGlobal->diskSize = deviceParentAndSizeMap[keyName].second; } return siGlobal->diskSize; #endif return -1; } /*! @~english DSysInfo::bootTime * @~english \sa DSysInfo::uptime * @~english \return the boot time(currentDateTime - uptime) */ QDateTime DSysInfo::bootTime() { qint64 ut = uptime(); return ut > 0 ? QDateTime::currentDateTime().addSecs(-ut) : QDateTime(); } /*! @~english DSysInfo::shutdownTime * @~english \return the last shutdown time */ QDateTime DSysInfo::shutdownTime() { QDateTime dt; #if defined Q_OS_LINUX QProcess lastx; lastx.start("last", {"-x", "-F" }, QIODevice::ReadOnly); if (!lastx.waitForFinished()) { qWarning() << lastx.errorString(); return QDateTime(); } while (lastx.canReadLine()) { const QByteArray data = lastx.readLine(1024); //shutdown system down 4.19.0-amd64-des Fri Sep 30 17:53:17 2022 - Sat Oct 8 08:32:47 2022 (7+14:39) if (data.startsWith("shutdown")) { #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) QString timeFmt = QString(data).split(' ', Qt::SkipEmptyParts).mid(4, 5).join(' '); #else QString timeFmt = QString(data).split(' ', QString::SkipEmptyParts).mid(4, 5).join(' '); #endif dt = QDateTime::fromString(timeFmt); break; } } #else #endif return dt; } /*! @~english DSysInfo::uptime * @~english \return the up time (/proc/uptime) */ qint64 DSysInfo::uptime() { #if defined Q_OS_LINUX QFile file("/proc/uptime"); if (!file.open(QFile::ReadOnly)) { qWarning() << file.errorString(); return -1; } QByteArray upTime = file.readAll(); bool ok = false; qint64 sec = qCeil(upTime.split(' ').value(0).toDouble(&ok)); // [0]: uptime [1]: idletime return ok ? sec : -1; #elif defined Q_OS_WIN64 return GetTickCount64(); #elif defined Q_OS_WIN32 return GetTickCount(); #else return -1; #endif } /*! @~english DSysInfo::arch * @~english \return the architecture of processor */ DSysInfo::Arch DSysInfo::arch() { #if defined(__x86_64__) return X86_64; #elif defined(__i386__) return X86; #elif defined(__powerpc64__) # if __BYTE_ORDER == __BIG_ENDIAN return PPC64; # else return PPC64_LE; # endif #elif defined(__powerpc__) # if __BYTE_ORDER == __BIG_ENDIAN return PPC; # else return PPC_LE; # endif #elif defined(__ia64__) return IA64; #elif defined(__hppa64__) return PARISC64; #elif defined(__hppa__) return PARISC; #elif defined(__s390x__) return S390X; #elif defined(__s390__) return S390; #elif defined(__sparc__) && defined (__arch64__) return SPARC64; #elif defined(__sparc__) return SPARC; #elif defined(__mips64) && defined(__LP64__) # if __BYTE_ORDER == __BIG_ENDIAN return MIPS64; # else return MIPS64_LE; # endif #elif defined(__mips64) # if __BYTE_ORDER == __BIG_ENDIAN return MIPS64; # else return MIPS64_LE; # endif #elif defined(__mips__) # if __BYTE_ORDER == __BIG_ENDIAN return MIPS; # else return MIPS_LE; # endif #elif defined(__alpha__) return ALPHA; #elif defined(__aarch64__) # if __BYTE_ORDER == __BIG_ENDIAN return ARM64_BE; # else return ARM64; # endif #elif defined(__arm__) # if __BYTE_ORDER == __BIG_ENDIAN return ARM_BE; # else return ARM; # endif #elif defined(__sh64__) return SH64; #elif defined(__sh__) return SH; #elif defined(__loongarch64) return LOONGARCH64; #elif defined(__m68k__) return M68K; #elif defined(__tilegx__) return TILEGX; #elif defined(__cris__) return CRIS; #elif defined(__nios2__) return NIOS2; #elif defined(__riscv) # if __SIZEOF_POINTER__ == 4 return RISCV32; # elif __SIZEOF_POINTER__ == 8 return RISCV64; # else # error "Unrecognized riscv architecture variant" # endif #elif defined(__arc__) # if __BYTE_ORDER == __BIG_ENDIAN return ARC_BE; # else return ARC; # endif #elif defined(__sw_64__) return SW_64; #else # error "Please register your architecture here!" #endif } DCORE_END_NAMESPACE dtkcore-5.7.12/src/dtkcore_global.cpp000066400000000000000000000007621476226660600175330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtkcore_global.h" #include #include #if (!defined DTK_VERSION) || (!defined DTK_VERSION_STR) #error "DTK_VERSION or DTK_VERSION_STR not defined!" #endif int dtkVersion() { return DTK_VERSION; } const char *dtkVersionString() { #ifdef QT_DEBUG qWarning() << "Use DTK_VERSION_STR instead."; #endif return ""; // DTK_VERSION_STR; } dtkcore-5.7.12/src/filesystem/000077500000000000000000000000001476226660600162335ustar00rootroot00000000000000dtkcore-5.7.12/src/filesystem/dbasefilewatcher.cpp000066400000000000000000000072701476226660600222410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dbasefilewatcher.h" #include "private/dbasefilewatcher_p.h" #include #include DCORE_BEGIN_NAMESPACE QList DBaseFileWatcherPrivate::watcherList; DBaseFileWatcherPrivate::DBaseFileWatcherPrivate(DBaseFileWatcher *qq) : DObjectPrivate(qq) { } /*! @~english @class Dtk::Core::DBaseFileWatcher @ingroup dtkcore @brief The DBaseFileWatcher class provides an interface for monitoring files and directories for modifications. */ DBaseFileWatcher::~DBaseFileWatcher() { stopWatcher(); DBaseFileWatcherPrivate::watcherList.removeOne(this); } QUrl DBaseFileWatcher::fileUrl() const { Q_D(const DBaseFileWatcher); return d->url; } /*! @~english @brief Let file watcher start watching file changes. @sa stopWatcher(), restartWatcher() */ bool DBaseFileWatcher::startWatcher() { Q_D(DBaseFileWatcher); if (d->started) return true; if (d->start()) { d->started = true; return true; } return false; } /*! @~english @brief Stop watching file changes. @sa startWatcher(), restartWatcher() */ bool DBaseFileWatcher::stopWatcher() { Q_D(DBaseFileWatcher); if (!d->started) return false; if (d->stop()) { d->started = false; return true; } return false; } /*! @~english @brief Stop file watcher and then restart it to watching file changes. @sa startWatcher(), stopWatcher() */ bool DBaseFileWatcher::restartWatcher() { bool ok = stopWatcher(); return ok && startWatcher(); } /*! @~english @brief Set enable file watcher for \a subfileUrl or not @param[in] subfileUrl The given url @param[in] enabled Enable file change watching or not. */ void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled) { Q_UNUSED(subfileUrl) Q_UNUSED(enabled) } /*! @~english @brief Emit a signal about \a targetUrl got a \a signal with \a arg1 Example usage: @code DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileDeleted, QUrl("bookmark:///bookmarkFile1")); @endcode @return 成功发送返回 true,否则返回 false. */ bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType1 signal, const QUrl &arg1) { if (!signal) return false; bool ok = false; for (DBaseFileWatcher *watcher : DBaseFileWatcherPrivate::watcherList) { if (watcher->fileUrl() == targetUrl) { ok = true; (watcher->*signal)(arg1); } } return ok; } /*! @~english @brief Emit a signal about \a targetUrl got a \a signal with \a arg1 and \a arg2 Example usage: @code DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileMoved, QUrl("bookmark:///bookmarkFile1"), QUrl("bookmark:///NewNameFile1")); @endcode */ bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType2 signal, const QUrl &arg1, const QUrl &arg2) { if (!signal) return false; bool ok = false; for (DBaseFileWatcher *watcher : DBaseFileWatcherPrivate::watcherList) { if (watcher->fileUrl() == targetUrl) { ok = true; (watcher->*signal)(arg1, arg2); } } return ok; } DBaseFileWatcher::DBaseFileWatcher(DBaseFileWatcherPrivate &dd, const QUrl &url, QObject *parent) : QObject(parent) , DObject(dd) { Q_ASSERT(url.isValid()); d_func()->url = url; DBaseFileWatcherPrivate::watcherList << this; } DCORE_END_NAMESPACE //#include "moc_dbasefilewatcher.cpp" dtkcore-5.7.12/src/filesystem/dcapfile.cpp000066400000000000000000000200661476226660600205120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dcapfile.h" #include "dobject_p.h" #include "private/dcapfsfileengine_p.h" #include DCORE_BEGIN_NAMESPACE extern QString _d_cleanPath(const QString &path); extern bool _d_isSubFileOf(const QString &filePath, const QString &directoryPath); class DCapFilePrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DCapFile) public: DCapFilePrivate(DCapFile *qq, const QString &fileName = QString()); static bool canReadWrite(const QString &path); QString fileName; }; DCapFilePrivate::DCapFilePrivate(DCapFile *qq, const QString &fileName) : DObjectPrivate(qq) , fileName(fileName) { } bool DCapFilePrivate::canReadWrite(const QString &path) { DCapFSFileEngine engine(path); return engine.canReadWrite(path); } DCapFile::DCapFile(QObject *parent) : QFile(parent) , DObject(*new DCapFilePrivate(this)) { } DCapFile::DCapFile(const QString &name, QObject *parent) : QFile(name, parent) , DObject(*new DCapFilePrivate(this, name)) { } DCapFile::~DCapFile() { } void DCapFile::setFileName(const QString &name) { D_D(DCapFile); d->fileName = name; return QFile::setFileName(name); } bool DCapFile::exists() const { D_DC(DCapFile); if (!d->canReadWrite(d->fileName)) return false; return QFile::exists(); } bool DCapFile::exists(const QString &fileName) { return DCapFile(fileName).exists(); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DCapFile::readLink() const { D_DC(DCapFile); if (!d->canReadWrite(d->fileName)) return {}; return QFile::symLinkTarget(); } #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QString DCapFile::symLinkTarget() const { return QFile::symLinkTarget(); } #endif bool DCapFile::remove() { D_D(DCapFile); if (!d->canReadWrite(d->fileName)) return false; return QFile::remove(); } bool DCapFile::remove(const QString &fileName) { return DCapFile(fileName).remove(); } #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) bool DCapFile::moveToTrash() { D_D(DCapFile); if (!d->canReadWrite(d->fileName)) return false; return QFile::moveToTrash(); } bool DCapFile::moveToTrash(const QString &fileName, QString *pathInTrash) { DCapFile file(fileName); if (file.moveToTrash()) { if (pathInTrash) *pathInTrash = file.fileName(); return true; } return false; } #endif bool DCapFile::rename(const QString &newName) { D_D(DCapFile); if (!d->canReadWrite(newName)) return false; return QFile::rename(newName); } bool DCapFile::rename(const QString &oldName, const QString &newName) { if (!DCapFilePrivate::canReadWrite(oldName)) return false; return DCapFile(oldName).rename(newName); } bool DCapFile::link(const QString &newName) { D_D(DCapFile); if (!d->canReadWrite(newName)) return false; return QFile::link(newName); } bool DCapFile::link(const QString &oldName, const QString &newName) { if (!DCapFilePrivate::canReadWrite(oldName)) return false; return DCapFile(oldName).link(newName); } bool DCapFile::copy(const QString &newName) { D_D(DCapFile); if (!d->canReadWrite(newName)) return false; return QFile::copy(newName); } bool DCapFile::copy(const QString &fileName, const QString &newName) { if (!DCapFilePrivate::canReadWrite(fileName)) return false; return DCapFile(fileName).copy(newName); } bool DCapFile::open(QIODevice::OpenMode flags) { D_D(DCapFile); if (!d->canReadWrite(d->fileName)) return false; return QFile::open(flags); } bool DCapFile::resize(qint64 sz) { D_D(DCapFile); if (!d->canReadWrite(d->fileName)) return false; return QFile::resize(sz); } bool DCapFile::resize(const QString &fileName, qint64 sz) { return DCapFile(fileName).resize(sz); } bool DCapFile::open(FILE *, QIODevice::OpenMode, QFileDevice::FileHandleFlags) { return false; } bool DCapFile::open(int, QIODevice::OpenMode, QFileDevice::FileHandleFlags) { return false; } class DCapDirPrivate : public QSharedData { public: DCapDirPrivate(QString filePath); explicit DCapDirPrivate(const DCapDirPrivate ©); QString filePath; }; DCapDirPrivate::DCapDirPrivate(QString filePath) : filePath(filePath) { } DCapDirPrivate::DCapDirPrivate(const DCapDirPrivate ©) : QSharedData(copy) , filePath(copy.filePath) { } DCapDir::DCapDir(const DCapDir &dir) : QDir(dir) , dd_ptr(dir.dd_ptr) { } DCapDir::DCapDir(const QString &path) : QDir(path) , dd_ptr(new DCapDirPrivate(path)) { } DCapDir::DCapDir(const QString &path, const QString &nameFilter, QDir::SortFlags sort, QDir::Filters filter) : QDir(path, nameFilter, sort, filter) , dd_ptr(new DCapDirPrivate(path)) { } DCapDir::~DCapDir() { } void DCapDir::setPath(const QString &path) { dd_ptr = new DCapDirPrivate(path); return QDir::setPath(path); } bool DCapDir::cd(const QString &dirName) { auto old_d = d_ptr; bool ret = QDir::cd(dirName); if (!ret) return ret; // take the new path. auto path = QDir::filePath(""); QScopedPointer fsEngine(new DCapFSFileEngine(path)); if (fsEngine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag) { dd_ptr = new DCapDirPrivate(path); return true; } d_ptr = old_d; return false; } QStringList DCapDir::entryList(DCapDir::Filters filters, DCapDir::SortFlags sort) const { const QDirPrivate* d = d_ptr.constData(); return entryList(d->nameFilters, filters, sort); } QStringList DCapDir::entryList(const QStringList &nameFilters, DCapDir::Filters filters, DCapDir::SortFlags sort) const { if (!DCapFilePrivate::canReadWrite(dd_ptr->filePath)) return {}; return QDir::entryList(nameFilters, filters, sort); } QFileInfoList DCapDir::entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const { const QDirPrivate* d = d_ptr.constData(); return entryInfoList(d->nameFilters, filters, sort); } QFileInfoList DCapDir::entryInfoList(const QStringList &nameFilters, DCapDir::Filters filters, DCapDir::SortFlags sort) const { if (!DCapFilePrivate::canReadWrite(dd_ptr->filePath)) return {}; return QDir::entryInfoList(nameFilters, filters, sort); } bool DCapDir::mkdir(const QString &dirName) const { QString fn = filePath(dirName); if (!DCapFilePrivate::canReadWrite(fn)) return false; return QDir::mkdir(dirName); } bool DCapDir::rmdir(const QString &dirName) const { QString fn = filePath(dirName); if (!DCapFilePrivate::canReadWrite(fn)) return false; return QDir::rmdir(dirName); } bool DCapDir::mkpath(const QString &dirPath) const { QString fn = filePath(dirPath); if (!DCapFilePrivate::canReadWrite(fn)) return false; return QDir::mkpath(dirPath); } bool DCapDir::rmpath(const QString &dirPath) const { QString fn = filePath(dirPath); if (!DCapFilePrivate::canReadWrite(fn)) return false; return QDir::rmpath(dirPath); } bool DCapDir::exists() const { if (!DCapFilePrivate::canReadWrite(dd_ptr->filePath)) return false; return QDir::exists(); } bool DCapDir::exists(const QString &name) const { if (name.isEmpty()) { qWarning("DCapFile::exists: Empty or null file name"); return false; } return DCapFile::exists(filePath(name)); } bool DCapDir::remove(const QString &fileName) { if (fileName.isEmpty()) { qWarning("DCapDir::remove: Empty or null file name"); return false; } return DCapFile::remove(filePath(fileName)); } bool DCapDir::rename(const QString &oldName, const QString &newName) { if (oldName.isEmpty() || newName.isEmpty()) { qWarning("DCapDir::rename: Empty or null file name(s)"); return false; } DCapFile file(filePath(oldName)); if (!file.exists()) return false; return file.rename(filePath(newName)); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dcapfsfileengine.cpp000066400000000000000000000160671476226660600222370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "private/dcapfsfileengine_p.h" #include "private/dobject_p.h" #include "dvtablehook.h" #include "dcapmanager.h" #include DCORE_BEGIN_NAMESPACE extern QString _d_cleanPath(const QString &path); extern bool _d_isSubFileOf(const QString &filePath, const QString &directoryPath); #if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) static bool capDirIteraterHasNext(QAbstractFileEngineIterator *it) { const QStringList &paths = DCapManager::instance()->paths(); QString path = it->path(); QFileInfo info(path); if (info.isSymLink()) info = QFileInfo{info.symLinkTarget()}; bool ret = std::any_of(paths.cbegin(), paths.cend(), std::bind(_d_isSubFileOf, path, std::placeholders::_1)); if (!ret) return ret; return DVtableHook::callOriginalFun(it, &QAbstractFileEngineIterator::hasNext); } #endif #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) std::unique_ptr DCapFSFileEngineHandler::create(const QString &fileName) const #else QAbstractFileEngine *DCapFSFileEngineHandler::create(const QString &fileName) const #endif { #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) return std::unique_ptr(new DCapFSFileEngine(fileName)); #else return new DCapFSFileEngine(fileName); #endif } class DCapFSFileEnginePrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DCapFSFileEngine) public: DCapFSFileEnginePrivate(const QString &file, DCapFSFileEngine *qq); bool canReadWrite(const QString &path) const; QString file; }; DCapFSFileEnginePrivate::DCapFSFileEnginePrivate(const QString &file, DCapFSFileEngine *qq) : DObjectPrivate(qq) , file(file) { } bool DCapFSFileEnginePrivate::canReadWrite(const QString &path) const { if (path.isEmpty()) return false; QString target = path; if (path == this->file) { D_QC(DCapFSFileEngine); target = q->fileName(DCapFSFileEngine::AbsoluteName); } else { QFSFileEngine engine(path); target = engine.fileName(DCapFSFileEngine::AbsoluteName); } auto paths = DCapManager::instance()->paths(); return std::any_of(paths.cbegin(), paths.cend(), std::bind(_d_isSubFileOf, target, std::placeholders::_1)); } DCapFSFileEngine::DCapFSFileEngine(const QString &file) : QFSFileEngine(file) , DObject(*new DCapFSFileEnginePrivate(file, this)) { } DCapFSFileEngine::~DCapFSFileEngine() { } #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool DCapFSFileEngine::open(QIODevice::OpenMode openMode, std::optional permissions) #else bool DCapFSFileEngine::open(QIODevice::OpenMode openMode) #endif { D_D(DCapFSFileEngine); if (!d->canReadWrite(d->file)) return false; #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) return QFSFileEngine::open(openMode, permissions); #else return QFSFileEngine::open(openMode); #endif } bool DCapFSFileEngine::remove() { D_D(DCapFSFileEngine); if (!d->canReadWrite(d->file)) return false; return QFSFileEngine::remove(); } bool DCapFSFileEngine::copy(const QString &newName) { D_D(DCapFSFileEngine); if (!d->canReadWrite(newName)) { // ###(Chen Bin): If false is returned here, QFile // will use the interface of qtemporaryfile for // file operation, and the restrictions in // DCapFSFileEngine cannot be used. And it will be // copied successfully. qWarning() << "DCapFSFileEngine: " << QStringLiteral("The file [%1] has no permission to copy!").arg(newName); return true; } return QFSFileEngine::copy(newName); } bool DCapFSFileEngine::rename(const QString &newName) { D_D(DCapFSFileEngine); if (!d->canReadWrite(newName)) return false; return QFSFileEngine::rename(newName); } bool DCapFSFileEngine::renameOverwrite(const QString &newName) { D_D(DCapFSFileEngine); if (!d->canReadWrite(newName)) return false; return QFSFileEngine::renameOverwrite(newName); } bool DCapFSFileEngine::link(const QString &newName) { D_D(DCapFSFileEngine); if (!d->canReadWrite(newName)) return false; return QFSFileEngine::link(newName); } #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool DCapFSFileEngine::mkdir(const QString &dirName, bool createParentDirectories, std::optional permissions) const #else bool DCapFSFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const #endif { D_DC(DCapFSFileEngine); if (!d->canReadWrite(dirName)) return false; #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) return QFSFileEngine::mkdir(dirName, createParentDirectories, permissions); #else return QFSFileEngine::mkdir(dirName, createParentDirectories); #endif } bool DCapFSFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const { D_DC(DCapFSFileEngine); if (!d->canReadWrite(dirName)) return false; return QFSFileEngine::rmdir(dirName, recurseParentDirectories); } QAbstractFileEngine::FileFlags DCapFSFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const { D_DC(DCapFSFileEngine); FileFlags ret = QFSFileEngine::fileFlags(type); if (ret | ExistsFlag) { if (!d->canReadWrite(d->file)) { ret &= ~ExistsFlag; } } return ret; } bool DCapFSFileEngine::cloneTo(QAbstractFileEngine *target) { D_DC(DCapFSFileEngine); const QString targetPath = target->fileName(DCapFSFileEngine::AbsolutePathName); if (!d->canReadWrite(targetPath)) return false; return QFSFileEngine::cloneTo(target); } bool DCapFSFileEngine::setSize(qint64 size) { D_D(DCapFSFileEngine); if (!d->canReadWrite(d->file)) return false; return QFSFileEngine::setSize(size); } QStringList DCapFSFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const { D_DC(DCapFSFileEngine); if (!d->canReadWrite(d->file)) return {}; return QFSFileEngine::entryList(filters, filterNames); } #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) QAbstractFileEngine::IteratorUniquePtr DCapFSFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) #elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) QAbstractFileEngine::IteratorUniquePtr DCapFSFileEngine::beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) #else QAbstractFileEngine::Iterator *DCapFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) #endif { #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) auto ret = QFSFileEngine::beginEntryList(path, filters, filterNames); #else auto ret = QFSFileEngine::beginEntryList(filters, filterNames); DVtableHook::overrideVfptrFun(ret, &QAbstractFileEngineIterator::hasNext, &capDirIteraterHasNext); #endif return ret; } bool DCapFSFileEngine::canReadWrite(const QString &path) const { D_DC(DCapFSFileEngine); return d->canReadWrite(path); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dcapmanager.cpp000066400000000000000000000074351476226660600212120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dcapmanager.h" #include "dobject_p.h" #include "dstandardpaths.h" #include "private/dcapfsfileengine_p.h" #include #include DCORE_BEGIN_NAMESPACE QString _d_cleanPath(const QString &path) { return path.size() < 2 || !path.endsWith(QDir::separator()) ? path : path.chopped(1); } bool _d_isSubFileOf(const QString &filePath, const QString &directoryPath) { QString path = _d_cleanPath(filePath); bool ret = path.startsWith(directoryPath); return ret; } static QStringList defaultWriteablePaths() { QStringList paths; int list[] = {QStandardPaths::AppConfigLocation, QStandardPaths::AppDataLocation, QStandardPaths::CacheLocation, QStandardPaths::TempLocation, #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QStandardPaths::DataLocation, #endif QStandardPaths::GenericConfigLocation, QStandardPaths::HomeLocation, QStandardPaths::MusicLocation, QStandardPaths::DocumentsLocation, QStandardPaths::MoviesLocation, QStandardPaths::PicturesLocation, QStandardPaths::DownloadLocation}; for (uint i = 0; i < sizeof (list) / sizeof (int); ++i) { const QString &path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation(list[i])); if (path.isEmpty()) continue; paths.append(path); } for (int i = 0; i <= static_cast(DStandardPaths::XDG::RuntimeDir); ++i) { const QString &path = DStandardPaths::path(DStandardPaths::XDG(i)); if (path.isEmpty()) continue; paths.append(path); } for (int i = 0; i <= static_cast(DStandardPaths::DSG::DataDir); ++i) { const QStringList &pathList = DStandardPaths::paths(DStandardPaths::DSG(i)); if (pathList.isEmpty()) continue; for (auto path : pathList) { if (path.isEmpty() || paths.contains(path)) continue; paths.append(path); } } return paths; } class DCapManagerPrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DCapManager) public: DCapManagerPrivate(DCapManager *qq); QStringList pathList; }; class DCapManager_ : public DCapManager {}; Q_GLOBAL_STATIC(DCapManager_, capManager) DCapManagerPrivate::DCapManagerPrivate(DCapManager *qq) : DObjectPrivate(qq) { pathList = defaultWriteablePaths(); } DCapManager::DCapManager() : DObject(*new DCapManagerPrivate(this)) { } DCapManager *DCapManager::instance() { return capManager; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void DCapManager::registerFileEngine() { } void DCapManager::unregisterFileEngine() { } #endif void DCapManager::appendPath(const QString &path) { D_D(DCapManager); const QString &targetPath = _d_cleanPath(path); bool exist = std::any_of(d->pathList.cbegin(), d->pathList.cend(), std::bind(_d_isSubFileOf, targetPath, std::placeholders::_1)); if (exist) return; d->pathList.append(targetPath); } void DCapManager::appendPaths(const QStringList &pathList) { for (auto path : pathList) appendPath(path); } void DCapManager::removePath(const QString &path) { D_D(DCapManager); const QString &targetPath = _d_cleanPath(path); if (!d->pathList.contains(targetPath)) return; d->pathList.removeOne(targetPath); } void DCapManager::removePaths(const QStringList &paths) { for (auto path : paths) removePath(path); } QStringList DCapManager::paths() const { D_DC(DCapManager); return d->pathList; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dfilesystemwatcher_dummy.cpp000066400000000000000000000163411476226660600240650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfilesystemwatcher.h" #include "private/dfilesystemwatcher_dummy_p.h" DCORE_BEGIN_NAMESPACE DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq) : DObjectPrivate(qq) { } DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate() { } /*! @~english @class Dtk::Core::DFileSystemWatcher \inmodule dtkcore \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications. DFileSystemWatcher monitors the file system for changes to files and directories by watching a list of specified paths. Call addPath() to watch a particular file or directory. Multiple paths can be added using the addPaths() function. Existing paths can be removed by using the removePath() and removePaths() functions. DFileSystemWatcher examines each path added to it. Files that have been added to the DFileSystemWatcher can be accessed using the files() function, and directories using the directories() function. The fileChanged() signal is emitted when a file has been modified, renamed or removed from disk. Similarly, the directoryChanged() signal is emitted when a directory or its contents is modified or removed. Note that DFileSystemWatcher stops monitoring files once they have been renamed or removed from disk, and directories once they have been removed from disk. @note On systems running a Linux kernel without inotify support, file systems that contain watched paths cannot be unmounted. @note Windows CE does not support directory monitoring by default as this depends on the file system driver installed. @note The act of monitoring files and directories for modifications consumes system resources. This implies there is a limit to the number of files and directories your process can monitor simultaneously. On all BSD variants, for example, an open file descriptor is required for each monitored file. Some system limits the number of open file descriptors to 256 by default. This means that addPath() and addPaths() will fail if your process tries to add more than 256 files or directories to the file system monitor. Also note that your process may have other file descriptors open in addition to the ones for files being monitored, and these other open descriptors also count in the total. OS X uses a different backend and does not suffer from this issue. */ /*! @~english Constructs a new file system watcher object with the given \a parent. */ DFileSystemWatcher::DFileSystemWatcher(QObject *parent) : QObject(parent) , DObject() { } /*! @~english Constructs a new file system watcher object with the given \a parent which monitors the specified \a paths list. */ DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent) : DFileSystemWatcher(parent) { addPaths(paths); } /*! @~english Destroys the file system watcher. */ DFileSystemWatcher::~DFileSystemWatcher() { } /*! @~english Adds \a path to the file system watcher if \a path exists. The path is not added if it does not exist, or if it is already being monitored by the file system watcher. If \a path specifies a directory, the directoryChanged() signal will be emitted when \a path is modified or removed from disk; otherwise the fileChanged() signal is emitted when \a path is modified, renamed or removed. If the watch was successful, true is returned. Reasons for a watch failure are generally system-dependent, but may include the resource not existing, access failures, or the total watch count limit, if the platform has one. @note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit is been reached, \a path will not be monitored, and false is returned. @sa addPaths(), removePath() */ bool DFileSystemWatcher::addPath(const QString &path) { return false; } /*! @~english Adds each path in \a paths to the file system watcher. Paths are not added if they not exist, or if they are already being monitored by the file system watcher. If a path specifies a directory, the directoryChanged() signal will be emitted when the path is modified or removed from disk; otherwise the fileChanged() signal is emitted when the path is modified, renamed, or removed. The return value is a list of paths that could not be watched. Reasons for a watch failure are generally system-dependent, but may include the resource not existing, access failures, or the total watch count limit, if the platform has one. @note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit has been reached, the excess \a paths will not be monitored, and they will be added to the returned QStringList. @sa addPath(), removePaths() */ QStringList DFileSystemWatcher::addPaths(const QStringList &paths) { return QStringList(); } /*! @~english Removes the specified \a path from the file system watcher. If the watch is successfully removed, true is returned. Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. @sa removePaths(), addPath() */ bool DFileSystemWatcher::removePath(const QString &path) { return false; } /*! @~english Removes the specified \a paths from the file system watcher. The return value is a list of paths which were not able to be unwatched successfully. Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. @sa removePath(), addPaths() */ QStringList DFileSystemWatcher::removePaths(const QStringList &paths) { return QStringList(); } /*! @~english @fn void DFileSystemWatcher::fileChanged(const QString &path) This signal is emitted when the file at the specified \a path is modified, renamed or removed from disk. @sa directoryChanged() */ /*! @~english @fn void DFileSystemWatcher::directoryChanged(const QString &path) This signal is emitted when the directory at a specified \a path is modified (e.g., when a file is added or deleted) or removed from disk. Note that if there are several changes during a short period of time, some of the changes might not Q_EMIT this signal. However, the last change in the sequence of changes will always generate this signal. @sa fileChanged() */ /*! @~english @fn QStringList DFileSystemWatcher::directories() const Returns a list of paths to directories that are being watched. @sa files() */ /*! @~english @fn QStringList DFileSystemWatcher::files() const Returns a list of paths to files that are being watched. @sa directories() */ QStringList DFileSystemWatcher::directories() const { return QStringList(); } QStringList DFileSystemWatcher::files() const { return QStringList(); } DCORE_END_NAMESPACE #include "moc_dfilesystemwatcher.cpp" dtkcore-5.7.12/src/filesystem/dfilesystemwatcher_linux.cpp000066400000000000000000000475021476226660600240740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfilesystemwatcher.h" #include "private/dfilesystemwatcher_linux_p.h" #include #include #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq) : DObjectPrivate(qq) , inotifyFd(fd) , notifier(fd, QSocketNotifier::Read, qq) { fcntl(inotifyFd, F_SETFD, FD_CLOEXEC); qq->connect(¬ifier, SIGNAL(activated(int)), qq, SLOT(_q_readFromInotify())); } DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate() { notifier.setEnabled(false); Q_FOREACH (int id, pathToID) inotify_rm_watch(inotifyFd, id < 0 ? -id : id); ::close(inotifyFd); } QStringList DFileSystemWatcherPrivate::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) { QStringList p = paths; QMutableListIterator it(p); while (it.hasNext()) { QString path = it.next(); QFileInfo fi(path); bool isDir = fi.isDir(); if (isDir) { if (directories->contains(path)) continue; } else { if (files->contains(path)) continue; } int wd = inotify_add_watch(inotifyFd, QFile::encodeName(path), (isDir ? (0 | IN_ATTRIB | IN_MOVE | IN_MOVE_SELF | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY ) : (0 | IN_ATTRIB | IN_CLOSE_WRITE | IN_MODIFY | IN_MOVE | IN_MOVE_SELF | IN_DELETE_SELF ))); if (wd < 0) { perror("DFileSystemWatcherPrivate::addPaths: inotify_add_watch failed"); continue; } it.remove(); int id = isDir ? -wd : wd; if (id < 0) { directories->append(path); } else { files->append(path); } pathToID.insert(path, id); idToPath.insert(id, path); } return p; } QStringList DFileSystemWatcherPrivate::removePaths(const QStringList &paths, QStringList *files, QStringList *directories) { QStringList p = paths; QMutableListIterator it(p); while (it.hasNext()) { QString path = it.next(); int id = pathToID.take(path); for (auto hit = idToPath.find(id); hit != idToPath.end() && hit.key() == id; ++hit) { if (hit.value() == path) { idToPath.erase(hit); break; } } it.remove(); if (!idToPath.contains(id)) { int wd = id < 0 ? -id : id; //qDebug() << "removing watch for path" << path << "wd" << wd; inotify_rm_watch(inotifyFd, wd); } if (id < 0) { directories->removeAll(path); } else { files->removeAll(path); } } return p; } void DFileSystemWatcherPrivate::_q_readFromInotify() { Q_Q(DFileSystemWatcher); // qDebug() << "QInotifyFileSystemWatcherEngine::readFromInotify"; int buffSize = 0; ioctl(inotifyFd, FIONREAD, (char *) &buffSize); QVarLengthArray buffer(buffSize); buffSize = read(inotifyFd, buffer.data(), buffSize); char *at = buffer.data(); char * const end = at + buffSize; QList eventList; QMultiHash batch_pathmap; /// only save event: IN_MOVE_TO QMultiMap cookieToFilePath; QMultiMap cookieToFileName; QSet hasMoveFromByCookie; #ifdef QT_DEBUG int exist_count = 0; #endif while (at < end) { inotify_event *event = reinterpret_cast(at); QStringList paths; at += sizeof(inotify_event) + event->len; int id = event->wd; paths = idToPath.values(id); if (paths.empty()) { // perhaps a directory? id = -id; paths = idToPath.values(id); if (paths.empty()) continue; } if (!(event->mask & IN_MOVED_TO) || !hasMoveFromByCookie.contains(event->cookie)) { auto it = std::find_if(eventList.begin(), eventList.end(), [event](inotify_event *e){ return event->wd == e->wd && event->mask == e->mask && event->cookie == e->cookie && event->len == e->len && !strcmp(event->name, e->name); }); if (it==eventList.end()) { eventList.append(event); } #ifdef QT_DEBUG else { qDebug() << "exist event:" << "event->wd" << event->wd << "event->mask" << event->mask << "event->cookie" << event->cookie << "exist counts " << ++exist_count; } #endif const QList bps = batch_pathmap.values(id); for (auto &path : paths) { if (!bps.contains(path)) { batch_pathmap.insert(id, path); } } } if (event->mask & IN_MOVED_TO) { for (auto &path : paths) { cookieToFilePath.insert(event->cookie, path); } cookieToFileName.insert(event->cookie, QString::fromUtf8(event->name)); } if (event->mask & IN_MOVED_FROM) hasMoveFromByCookie << event->cookie; } // qDebug() << "event count:" << eventList.count(); QList::const_iterator it = eventList.constBegin(); while (it != eventList.constEnd()) { const inotify_event &event = **it; ++it; // qDebug() << "inotify event, wd" << event.wd << "cookie" << event.cookie << "mask" << hex << event.mask; int id = event.wd; QStringList paths = batch_pathmap.values(id); if (paths.empty()) { id = -id; paths = batch_pathmap.values(id); if (paths.empty()) continue; } const QString &name = QString::fromUtf8(event.name); for (auto &path : paths) { // qDebug() << "event for path" << path; // /// TODO: Existence of invalid utf8 characters QFile can not read the file information // if (event.name != QString::fromLocal8Bit(event.name).toLocal8Bit()) { // if (event.mask & (IN_CREATE | IN_MOVED_TO)) { // DFMGlobal::fileNameCorrection(path); // } // } if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) { do { if (event.mask & IN_MOVE_SELF) { QMultiMap::const_iterator iterator = cookieToFilePath.constBegin(); bool isMove = false; while (iterator != cookieToFilePath.constEnd()) { const QString &_path = iterator.value(); const QString &_name = cookieToFileName.value(iterator.key()); if (QFileInfo(_path + QDir::separator() + _name) == QFileInfo(path)) { isMove = true; break; } ++iterator; } if (isMove) break; } /// Keep watcher // pathToID.remove(path); // idToPath.remove(id, getPathFromID(id)); // if (!idToPath.contains(id)) // inotify_rm_watch(inotifyFd, event.wd); // if (id < 0) // onDirectoryChanged(path, true); // else // onFileChanged(path, true); Q_EMIT q->fileDeleted(path, QString(), DFileSystemWatcher::QPrivateSignal()); } while (false); } else { if (id < 0) onDirectoryChanged(path, false); else onFileChanged(path, false); } QString filePath = path; if (id < 0) { if (path.endsWith(QDir::separator())) filePath = path + name; else filePath = path + QDir::separator() + name; } if (event.mask & IN_CREATE) { // qDebug() << "IN_CREATE" << filePath << name; if (name.isEmpty()) { if (pathToID.contains(path)) { q->removePath(path); q->addPath(path); } } else if (pathToID.contains(filePath)) { q->removePath(filePath); q->addPath(filePath); } Q_EMIT q->fileCreated(path, name, DFileSystemWatcher::QPrivateSignal()); } if (event.mask & IN_DELETE) { // qDebug() << "IN_DELETE" << filePath; Q_EMIT q->fileDeleted(path, name, DFileSystemWatcher::QPrivateSignal()); } if (event.mask & IN_MOVED_FROM) { const QString toName = cookieToFileName.value(event.cookie); if (cookieToFilePath.values(event.cookie).empty()) { Q_EMIT q->fileMoved(path, name, QString(), QString(), DFileSystemWatcher::QPrivateSignal()); } else { for (QString &toPath : cookieToFilePath.values(event.cookie)) { // qDebug() << "IN_MOVED_FROM" << filePath << "to path:" << toPath << "to name:" << toName; Q_EMIT q->fileMoved(path, name, toPath, toName, DFileSystemWatcher::QPrivateSignal()); } } } if (event.mask & IN_MOVED_TO) { // qDebug() << "IN_MOVED_TO" << filePath; if (!hasMoveFromByCookie.contains(event.cookie)) Q_EMIT q->fileMoved(QString(), QString(), path, name, DFileSystemWatcher::QPrivateSignal()); } if (event.mask & IN_ATTRIB) { // qDebug() << "IN_ATTRIB" << event.mask << filePath; Q_EMIT q->fileAttributeChanged(path, name, DFileSystemWatcher::QPrivateSignal()); } /*only monitor file close event which is opend by write mode*/ if (event.mask & IN_CLOSE_WRITE) { // qDebug() << "IN_CLOSE_WRITE" << event.mask << filePath; Q_EMIT q->fileClosed(path, id < 0 ? name : QString(), DFileSystemWatcher::QPrivateSignal()); } if (event.mask & IN_MODIFY) { // qDebug() << "IN_MODIFY" << event.mask << filePath << name; Q_EMIT q->fileModified(path, name, DFileSystemWatcher::QPrivateSignal()); } } } } void DFileSystemWatcherPrivate::onFileChanged(const QString &path, bool removed) { Q_Q(DFileSystemWatcher); if (!files.contains(path)) { // the path was removed after a change was detected, but before we delivered the signal return; } if (removed) { files.removeAll(path); } // Q_EMIT q->fileChanged(path, DFileSystemWatcher::QPrivateSignal()); } void DFileSystemWatcherPrivate::onDirectoryChanged(const QString &path, bool removed) { Q_Q(DFileSystemWatcher); if (!directories.contains(path)) { // perhaps the path was removed after a change was detected, but before we delivered the signal return; } if (removed) { directories.removeAll(path); } // Q_EMIT q->directoryChanged(path, DFileSystemWatcher::QPrivateSignal()); } /*! \class Dtk::Core::DFileSystemWatcher \inmodule dtkcore \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications. DFileSystemWatcher monitors the file system for changes to files and directories by watching a list of specified paths. Call addPath() to watch a particular file or directory. Multiple paths can be added using the addPaths() function. Existing paths can be removed by using the removePath() and removePaths() functions. DFileSystemWatcher examines each path added to it. Files that have been added to the DFileSystemWatcher can be accessed using the files() function, and directories using the directories() function. \note On systems running a Linux kernel without inotify support, file systems that contain watched paths cannot be unmounted. \note Windows CE does not support directory monitoring by default as this depends on the file system driver installed. \note The act of monitoring files and directories for modifications consumes system resources. This implies there is a limit to the number of files and directories your process can monitor simultaneously. On all BSD variants, for example, an open file descriptor is required for each monitored file. Some system limits the number of open file descriptors to 256 by default. This means that addPath() and addPaths() will fail if your process tries to add more than 256 files or directories to the file system monitor. Also note that your process may have other file descriptors open in addition to the ones for files being monitored, and these other open descriptors also count in the total. OS X uses a different backend and does not suffer from this issue. */ /*! Constructs a new file system watcher object with the given \a parent. */ DFileSystemWatcher::DFileSystemWatcher(QObject *parent) : QObject(parent) , DObject() { int fd = -1; #ifdef IN_CLOEXEC fd = inotify_init1(IN_CLOEXEC | O_NONBLOCK); #endif if (fd == -1) { fd = inotify_init1(O_NONBLOCK); } if (fd != -1) { d_d_ptr.reset(new DFileSystemWatcherPrivate(fd, this)); } else { qCritical() << "inotify_init1 failed, and the DFileSystemWatcher is invalid." << strerror(errno); } } /*! Constructs a new file system watcher object with the given \a parent which monitors the specified \a paths list. */ DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent) : DFileSystemWatcher(parent) { addPaths(paths); } /*! Destroys the file system watcher. */ DFileSystemWatcher::~DFileSystemWatcher() { } /*! Adds \a path to the file system watcher if \a path exists. The path is not added if it does not exist, or if it is already being monitored by the file system watcher. If \a path specifies a directory, the directoryChanged() signal will be emitted when \a path is modified or removed from disk; otherwise the fileChanged() signal is emitted when \a path is modified, renamed or removed. If the watch was successful, true is returned. Reasons for a watch failure are generally system-dependent, but may include the resource not existing, access failures, or the total watch count limit, if the platform has one. \note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit is been reached, \a path will not be monitored, and false is returned. \sa addPaths(), removePath() */ bool DFileSystemWatcher::addPath(const QString &path) { const QStringList &paths = addPaths(QStringList(path)); return paths.isEmpty(); } /*! Adds each path in \a paths to the file system watcher. Paths are not added if they not exist, or if they are already being monitored by the file system watcher. If a path specifies a directory, the directoryChanged() signal will be emitted when the path is modified or removed from disk; otherwise the fileChanged() signal is emitted when the path is modified, renamed, or removed. The return value is a list of paths that could not be watched. Reasons for a watch failure are generally system-dependent, but may include the resource not existing, access failures, or the total watch count limit, if the platform has one. \note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit has been reached, the excess \a paths will not be monitored, and they will be added to the returned QStringList. \sa addPath(), removePaths() */ QStringList DFileSystemWatcher::addPaths(const QStringList &paths) { Q_D(DFileSystemWatcher); if (!d) return paths; QStringList p = paths; QMutableListIterator it(p); while (it.hasNext()) { const QString &path = it.next(); if (path.isEmpty()) { qWarning() << Q_FUNC_INFO << "the path is empty and it is not be watched"; it.remove(); } } if (p.isEmpty()) { qWarning() << Q_FUNC_INFO << "all path are filtered and they are not be watched, paths are " << paths; return paths; } p = d->addPaths(p, &d->files, &d->directories); return p; } /*! Removes the specified \a path from the file system watcher. If the watch is successfully removed, true is returned. Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. \sa removePaths(), addPath() */ bool DFileSystemWatcher::removePath(const QString &path) { const QStringList &paths = removePaths(QStringList(path)); return paths.isEmpty(); } /*! Removes the specified \a paths from the file system watcher. The return value is a list of paths which were not able to be unwatched successfully. Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. \sa removePath(), addPaths() */ QStringList DFileSystemWatcher::removePaths(const QStringList &paths) { Q_D(DFileSystemWatcher); if (!d) return paths; QStringList p = paths; QMutableListIterator it(p); while (it.hasNext()) { const QString &path = it.next(); if (path.isEmpty()) { qWarning() << Q_FUNC_INFO << "the path is empty and it is not be removed from watched list"; it.remove(); } } if (p.isEmpty()) { qWarning() << Q_FUNC_INFO << "all path are filtered and they are not be watched, paths are " << paths; return paths; } p = d->removePaths(p, &d->files, &d->directories); return p; } /*! \fn QStringList DFileSystemWatcher::directories() const Returns a list of paths to directories that are being watched. \sa files() */ /*! \fn QStringList DFileSystemWatcher::files() const Returns a list of paths to files that are being watched. \sa directories() */ QStringList DFileSystemWatcher::directories() const { Q_D(const DFileSystemWatcher); if (!d) return QStringList(); return d->directories; } QStringList DFileSystemWatcher::files() const { Q_D(const DFileSystemWatcher); if (!d) return QStringList(); return d->files; } DCORE_END_NAMESPACE #include "moc_dfilesystemwatcher.cpp" dtkcore-5.7.12/src/filesystem/dfilesystemwatcher_win.cpp000066400000000000000000000161751476226660600235340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfilesystemwatcher.h" #include "private/dfilesystemwatcher_win_p.h" DCORE_BEGIN_NAMESPACE DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq) : DObjectPrivate(qq) { } DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate() { } /*! \class Dtk::Core::DFileSystemWatcher \inmodule dtkcore \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications. DFileSystemWatcher monitors the file system for changes to files and directories by watching a list of specified paths. Call addPath() to watch a particular file or directory. Multiple paths can be added using the addPaths() function. Existing paths can be removed by using the removePath() and removePaths() functions. DFileSystemWatcher examines each path added to it. Files that have been added to the DFileSystemWatcher can be accessed using the files() function, and directories using the directories() function. The fileChanged() signal is emitted when a file has been modified, renamed or removed from disk. Similarly, the directoryChanged() signal is emitted when a directory or its contents is modified or removed. Note that DFileSystemWatcher stops monitoring files once they have been renamed or removed from disk, and directories once they have been removed from disk. \note On systems running a Linux kernel without inotify support, file systems that contain watched paths cannot be unmounted. \note Windows CE does not support directory monitoring by default as this depends on the file system driver installed. \note The act of monitoring files and directories for modifications consumes system resources. This implies there is a limit to the number of files and directories your process can monitor simultaneously. On all BSD variants, for example, an open file descriptor is required for each monitored file. Some system limits the number of open file descriptors to 256 by default. This means that addPath() and addPaths() will fail if your process tries to add more than 256 files or directories to the file system monitor. Also note that your process may have other file descriptors open in addition to the ones for files being monitored, and these other open descriptors also count in the total. OS X uses a different backend and does not suffer from this issue. \sa QFile, QDir */ /*! Constructs a new file system watcher object with the given \a parent. */ DFileSystemWatcher::DFileSystemWatcher(QObject *parent) : QObject(parent) , DObject() { } /*! Constructs a new file system watcher object with the given \a parent which monitors the specified \a paths list. */ DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent) : DFileSystemWatcher(parent) { addPaths(paths); } /*! Destroys the file system watcher. */ DFileSystemWatcher::~DFileSystemWatcher() { } /*! Adds \a path to the file system watcher if \a path exists. The path is not added if it does not exist, or if it is already being monitored by the file system watcher. If \a path specifies a directory, the directoryChanged() signal will be emitted when \a path is modified or removed from disk; otherwise the fileChanged() signal is emitted when \a path is modified, renamed or removed. If the watch was successful, true is returned. Reasons for a watch failure are generally system-dependent, but may include the resource not existing, access failures, or the total watch count limit, if the platform has one. \note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit is been reached, \a path will not be monitored, and false is returned. \sa addPaths(), removePath() */ bool DFileSystemWatcher::addPath(const QString &path) { return false; } /*! Adds each path in \a paths to the file system watcher. Paths are not added if they not exist, or if they are already being monitored by the file system watcher. If a path specifies a directory, the directoryChanged() signal will be emitted when the path is modified or removed from disk; otherwise the fileChanged() signal is emitted when the path is modified, renamed, or removed. The return value is a list of paths that could not be watched. Reasons for a watch failure are generally system-dependent, but may include the resource not existing, access failures, or the total watch count limit, if the platform has one. \note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit has been reached, the excess \a paths will not be monitored, and they will be added to the returned QStringList. \sa addPath(), removePaths() */ QStringList DFileSystemWatcher::addPaths(const QStringList &paths) { return QStringList(); } /*! Removes the specified \a path from the file system watcher. If the watch is successfully removed, true is returned. Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. \sa removePaths(), addPath() */ bool DFileSystemWatcher::removePath(const QString &path) { return false; } /*! Removes the specified \a paths from the file system watcher. The return value is a list of paths which were not able to be unwatched successfully. Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. \sa removePath(), addPaths() */ QStringList DFileSystemWatcher::removePaths(const QStringList &paths) { return QStringList(); } /*! \fn void DFileSystemWatcher::fileChanged(const QString &path) This signal is emitted when the file at the specified \a path is modified, renamed or removed from disk. \sa directoryChanged() */ /*! \fn void DFileSystemWatcher::directoryChanged(const QString &path) This signal is emitted when the directory at a specified \a path is modified (e.g., when a file is added or deleted) or removed from disk. Note that if there are several changes during a short period of time, some of the changes might not Q_EMIT this signal. However, the last change in the sequence of changes will always generate this signal. \sa fileChanged() */ /*! \fn QStringList DFileSystemWatcher::directories() const Returns a list of paths to directories that are being watched. \sa files() */ /*! \fn QStringList DFileSystemWatcher::files() const Returns a list of paths to files that are being watched. \sa directories() */ QStringList DFileSystemWatcher::directories() const { return QStringList(); } QStringList DFileSystemWatcher::files() const { return QStringList(); } DCORE_END_NAMESPACE #include "moc_dfilesystemwatcher.cpp" dtkcore-5.7.12/src/filesystem/dfilewatcher.cpp000066400000000000000000000174321476226660600214070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfilewatcher.h" #include "private/dbasefilewatcher_p.h" #include "dfilesystemwatcher.h" #include #include DCORE_BEGIN_NAMESPACE static QString joinFilePath(const QString &path, const QString &name) { if (path.endsWith(QDir::separator())) return path + name; return path + QDir::separator() + name; } class DFileWatcherPrivate : DBaseFileWatcherPrivate { public: DFileWatcherPrivate(DFileWatcher *qq) : DBaseFileWatcherPrivate(qq) {} bool start() Q_DECL_OVERRIDE; bool stop() Q_DECL_OVERRIDE; void _q_handleFileDeleted(const QString &path, const QString &parentPath); void _q_handleFileAttributeChanged(const QString &path, const QString &parentPath); void _q_handleFileMoved(const QString &from, const QString &fromParent, const QString &to, const QString &toParent); void _q_handleFileCreated(const QString &path, const QString &parentPath); void _q_handleFileModified(const QString &path, const QString &parentPath); void _q_handleFileClose(const QString &path, const QString &parentPath); static QString formatPath(const QString &path); QString path; QStringList watchFileList; static QMap filePathToWatcherCount; Q_DECLARE_PUBLIC(DFileWatcher) }; QMap DFileWatcherPrivate::filePathToWatcherCount; Q_GLOBAL_STATIC(DFileSystemWatcher, watcher_file_private) QStringList parentPathList(const QString &path) { QStringList list; QDir dir(path); list << path; while (dir.cdUp()) { list << dir.absolutePath(); } return list; } bool DFileWatcherPrivate::start() { Q_Q(DFileWatcher); started = true; Q_FOREACH (const QString &path, parentPathList(this->path)) { if (watchFileList.contains(path)) continue; if (filePathToWatcherCount.value(path, -1) <= 0) { if (!watcher_file_private->addPath(path)) { qWarning() << Q_FUNC_INFO << "start watch failed, file path =" << path; q->stopWatcher(); started = false; return false; } } watchFileList << path; filePathToWatcherCount[path] = filePathToWatcherCount.value(path, 0) + 1; } q->connect(watcher_file_private, &DFileSystemWatcher::fileDeleted, q, &DFileWatcher::onFileDeleted); q->connect(watcher_file_private, &DFileSystemWatcher::fileAttributeChanged, q, &DFileWatcher::onFileAttributeChanged); q->connect(watcher_file_private, &DFileSystemWatcher::fileMoved, q, &DFileWatcher::onFileMoved); q->connect(watcher_file_private, &DFileSystemWatcher::fileCreated, q, &DFileWatcher::onFileCreated); q->connect(watcher_file_private, &DFileSystemWatcher::fileModified, q, &DFileWatcher::onFileModified); q->connect(watcher_file_private, &DFileSystemWatcher::fileClosed, q, &DFileWatcher::onFileClosed); return true; } bool DFileWatcherPrivate::stop() { Q_Q(DFileWatcher); q->disconnect(watcher_file_private, 0, q, 0); bool ok = true; Q_FOREACH (const QString &path, watchFileList) { int count = filePathToWatcherCount.value(path, 0); --count; if (count <= 0) { filePathToWatcherCount.remove(path); watchFileList.removeOne(path); ok = ok && watcher_file_private->removePath(path); } else { filePathToWatcherCount[path] = count; } } return ok; } void DFileWatcherPrivate::_q_handleFileDeleted(const QString &path, const QString &parentPath) { if (path != this->path && parentPath != this->path) return; Q_Q(DFileWatcher); Q_EMIT q->fileDeleted(QUrl::fromLocalFile(path)); } void DFileWatcherPrivate::_q_handleFileAttributeChanged(const QString &path, const QString &parentPath) { if (path != this->path && parentPath != this->path) return; Q_Q(DFileWatcher); Q_EMIT q->fileAttributeChanged(QUrl::fromLocalFile(path)); } void DFileWatcherPrivate::_q_handleFileMoved(const QString &from, const QString &fromParent, const QString &to, const QString &toParent) { Q_Q(DFileWatcher); if ((fromParent == this->path && toParent == this->path) || from == this->path) { Q_EMIT q->fileMoved(QUrl::fromLocalFile(from), QUrl::fromLocalFile(to)); } else if (fromParent == this->path) { Q_EMIT q->fileDeleted(QUrl::fromLocalFile(from)); } else if (watchFileList.contains(from)) { Q_EMIT q->fileDeleted(url); } else if (toParent == this->path) { Q_EMIT q->subfileCreated(QUrl::fromLocalFile(to)); } } void DFileWatcherPrivate::_q_handleFileCreated(const QString &path, const QString &parentPath) { if (path != this->path && parentPath != this->path) return; Q_Q(DFileWatcher); Q_EMIT q->subfileCreated(QUrl::fromLocalFile(path)); } void DFileWatcherPrivate::_q_handleFileModified(const QString &path, const QString &parentPath) { if (path != this->path && parentPath != this->path) return; Q_Q(DFileWatcher); Q_EMIT q->fileModified(QUrl::fromLocalFile(path)); } void DFileWatcherPrivate::_q_handleFileClose(const QString &path, const QString &parentPath) { if (path != this->path && parentPath != this->path) return; Q_Q(DFileWatcher); Q_EMIT q->fileClosed(QUrl::fromLocalFile(path)); } QString DFileWatcherPrivate::formatPath(const QString &path) { QString p = QFileInfo(path).absoluteFilePath(); if (p.endsWith(QDir::separator())) p.chop(1); return p.isEmpty() ? path : p; } /*! @~english \class Dtk::Core::DFileWatcher \inmodule dtkcore \brief The DFileWatcher class provides an implementation of DBaseFileWatcher for monitoring files and directories for modifications. */ DFileWatcher::DFileWatcher(const QString &filePath, QObject *parent) : DBaseFileWatcher(*new DFileWatcherPrivate(this), QUrl::fromLocalFile(filePath), parent) { d_func()->path = DFileWatcherPrivate::formatPath(filePath); } void DFileWatcher::onFileDeleted(const QString &path, const QString &name) { if (name.isEmpty()) d_func()->_q_handleFileDeleted(path, QString()); else d_func()->_q_handleFileDeleted(joinFilePath(path, name), path); } void DFileWatcher::onFileAttributeChanged(const QString &path, const QString &name) { if (name.isEmpty()) d_func()->_q_handleFileAttributeChanged(path, QString()); else d_func()->_q_handleFileAttributeChanged(joinFilePath(path, name), path); } void DFileWatcher::onFileMoved(const QString &from, const QString &fname, const QString &to, const QString &tname) { QString fromPath, fpPath; QString toPath, tpPath; if (fname.isEmpty()) { fromPath = from; } else { fromPath = joinFilePath(from, fname); fpPath = from; } if (tname.isEmpty()) { toPath = to; } else { toPath = joinFilePath(to, tname); tpPath = to; } d_func()->_q_handleFileMoved(fromPath, fpPath, toPath, tpPath); } void DFileWatcher::onFileCreated(const QString &path, const QString &name) { d_func()->_q_handleFileCreated(joinFilePath(path, name), path); } void DFileWatcher::onFileModified(const QString &path, const QString &name) { if (name.isEmpty()) d_func()->_q_handleFileModified(path, QString()); else d_func()->_q_handleFileModified(joinFilePath(path, name), path); } void DFileWatcher::onFileClosed(const QString &path, const QString &name) { if (name.isEmpty()) d_func()->_q_handleFileClose(path, QString()); else d_func()->_q_handleFileClose(joinFilePath(path, name), path); } DCORE_END_NAMESPACE #include "moc_dfilewatcher.cpp" dtkcore-5.7.12/src/filesystem/dfilewatchermanager.cpp000066400000000000000000000060041476226660600227330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfilewatchermanager.h" #include "dfilewatcher.h" #include "base/private/dobject_p.h" #include #include DCORE_BEGIN_NAMESPACE class DFileWatcherManagerPrivate : public DObjectPrivate { public: DFileWatcherManagerPrivate(DFileWatcherManager *qq); QMap watchersMap; D_DECLARE_PUBLIC(DFileWatcherManager) }; DFileWatcherManagerPrivate::DFileWatcherManagerPrivate(DFileWatcherManager *qq) : DObjectPrivate(qq) { } /*! @~english \class Dtk::Core::DFileWatcherManager \inmodule dtkcore \brief The DFileWatcherManager class can help you manage file watchers and get signal when file got changed. */ DFileWatcherManager::DFileWatcherManager(QObject *parent) : QObject(parent) , DObject(*new DFileWatcherManagerPrivate(this)) { } DFileWatcherManager::~DFileWatcherManager() {} /*! @~english \brief Add file watcher for \a filePath to the file watcher manager. \return The file watcher which got created and added into the file watcher manager. */ DFileWatcher *DFileWatcherManager::add(const QString &filePath) { Q_D(DFileWatcherManager); DFileWatcher *watcher = d->watchersMap.value(filePath); if (watcher) { return watcher; } watcher = new DFileWatcher(filePath, this); connect(watcher, &DFileWatcher::fileAttributeChanged, this, [this](const QUrl &url) { Q_EMIT fileAttributeChanged(url.toLocalFile()); }); connect(watcher, &DFileWatcher::fileClosed, this, [this](const QUrl &url) { Q_EMIT fileClosed(url.toLocalFile()); }); connect(watcher, &DFileWatcher::fileDeleted, this, [this](const QUrl &url) { Q_EMIT fileDeleted(url.toLocalFile()); }); connect(watcher, &DFileWatcher::fileModified, this, [this](const QUrl &url) { Q_EMIT fileModified(url.toLocalFile()); }); connect(watcher, &DFileWatcher::fileMoved, this, [this](const QUrl &fromUrl, const QUrl &toUrl) { Q_EMIT fileMoved(fromUrl.toLocalFile(), toUrl.toLocalFile()); }); connect(watcher, &DFileWatcher::subfileCreated, this, [this](const QUrl &url) { Q_EMIT subfileCreated(url.toLocalFile()); }); d->watchersMap[filePath] = watcher; watcher->startWatcher(); return watcher; } /*! @~english \brief Remove file watcher for \a filePath from the file watcher manager. */ void DFileWatcherManager::remove(const QString &filePath) { Q_D(DFileWatcherManager); DFileWatcher *watcher = d->watchersMap.take(filePath); if (watcher) { watcher->deleteLater(); } } /*! @~english @brief Remove all file watcher */ void DFileWatcherManager::removeAll() { Q_D(DFileWatcherManager); for (auto it : d->watchersMap) { it->deleteLater(); } d->watchersMap.clear(); } /*! @~english @brief Show all file watcher */ QStringList DFileWatcherManager::watchedFiles() const { Q_D(const DFileWatcherManager); return d->watchersMap.keys(); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dpathbuf.cpp000066400000000000000000000035461476226660600205440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dpathbuf.h" /*! \class Dtk::Core::DPathBuf \inmodule dtkcore \brief Dtk::Core::DPathBuf cat path friendly and supoort multiplatform. \brief Dtk::Core::DPathBuf是一个用于跨平台拼接路径的辅助类. 它能够方便的写出链式结构的路径拼接代码。 \code DPathBuf logPath(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first()); logPath = logPath / ".cache" / "deepin" / "deepin-test-dtk" / "deepin-test-dtk.log"; \endcode */ DCORE_BEGIN_NAMESPACE /*! \fn DPathBuf DPathBuf::operator/(const QString &p) const \brief join path with operator / \a p is subpath \return a new DPathBuf with subpath p */ /*! \fn DPathBuf &DPathBuf::operator/=(const QString &p) \brief join path to self with operator /= \a p is subpath to join \return self object */ /*! \fn DPathBuf DPathBuf::operator/(const char *p) const \brief join path with operator / \a p is subpath \return a new DPathBuf with subpath p \sa Dtk::Core::DPathBuf::operator/(const QString &p) */ /*! \fn DPathBuf &DPathBuf::operator/=(const char *p) \brief join path to self with operator /= \a p is subpath to join \return self object \sa operator/=(const QString &p) */ /*! \fn DPathBuf &DPathBuf::join(const QString &p) \brief join add subpath p to self \a p is subpath to join \return slef object with subpath joined */ /*! \fn QString DPathBuf::toString() const \brief toString export native separators format string. \return string with native separators */ /*! \brief Create Dtk::Core::DPathBuf from string. \a path */ DPathBuf::DPathBuf(const QString &path) { m_path = QDir(path).absolutePath(); } DPathBuf::DPathBuf() : DPathBuf(QString()) { } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dstandardpaths.cpp000066400000000000000000000143561476226660600217540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dstandardpaths.h" #include #include #include DCORE_BEGIN_NAMESPACE class DSnapStandardPathsPrivate { public: inline static QString writableLocation(QStandardPaths::StandardLocation /*type*/) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); return env.value("SNAP_USER_COMMON"); } inline static QStringList standardLocations(QStandardPaths::StandardLocation type) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); switch (type) { case QStandardPaths::GenericDataLocation: { QString snapRoot = env.value("SNAP"); QString genericDataDir = snapRoot + PREFIX"/share/"; return QStringList() << genericDataDir; } default: break; } return QStringList() << env.value("SNAP_USER_COMMON"); } private: DSnapStandardPathsPrivate(); ~DSnapStandardPathsPrivate(); Q_DISABLE_COPY(DSnapStandardPathsPrivate) }; /*! \class Dtk::Core::DStandardPaths \inmodule dtkcore \brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口. \sa QStandardPaths */ /*! \enum Dtk::Core::DStandardPaths::Mode \brief DStandardPaths支持的路径产生模式。 \value Auto \brief 和Qt标准的行为表现一致。 \value Snap \brief 读取SNAP相关的环境变量,支持将配置存储在SNAP对应目录。 \value Test \brief 和Qt标准的行为表现一致,但是会开启测试模式,参考QStandardPaths::setTestModeEnabled。 */ static DStandardPaths::Mode s_mode = DStandardPaths::Auto; QString DStandardPaths::writableLocation(QStandardPaths::StandardLocation type) { switch (s_mode) { case Auto: case Test: return QStandardPaths::writableLocation(type); case Snap: return DSnapStandardPathsPrivate::writableLocation(type); } return QStandardPaths::writableLocation(type); } QStringList DStandardPaths::standardLocations(QStandardPaths::StandardLocation type) { switch (s_mode) { case Auto: case Test: return QStandardPaths::standardLocations(type); case Snap: return DSnapStandardPathsPrivate::standardLocations(type); } return QStandardPaths::standardLocations(type); } QString DStandardPaths::locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options) { return QStandardPaths::locate(type, fileName, options); } QStringList DStandardPaths::locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options) { return QStandardPaths::locateAll(type, fileName, options); } QString DStandardPaths::findExecutable(const QString &executableName, const QStringList &paths) { return QStandardPaths::findExecutable(executableName, paths); } void DStandardPaths::setMode(DStandardPaths::Mode mode) { s_mode = mode; QStandardPaths::setTestModeEnabled(mode == Test); } // https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/issues/21 QString DStandardPaths::homePath() { const QByteArray &home = qgetenv("HOME"); if (!home.isEmpty()) return QString::fromLocal8Bit(home); return homePath(getuid()); } QString DStandardPaths::path(DStandardPaths::XDG type) { switch (type) { case XDG::DataHome: { const QByteArray &path = qgetenv("XDG_DATA_HOME"); if (!path.isEmpty()) return QString::fromLocal8Bit(path); return homePath() + QStringLiteral("/.local/share"); } case XDG::CacheHome: { const QByteArray &path = qgetenv("XDG_CACHE_HOME"); if (!path.isEmpty()) return QString::fromLocal8Bit(path); return homePath() + QStringLiteral("/.cache"); } case XDG::ConfigHome: { const QByteArray &path = qgetenv("XDG_CONFIG_HOME"); if (!path.isEmpty()) return QString::fromLocal8Bit(path); return homePath() + QStringLiteral("/.config"); } case XDG::RuntimeDir: { const QByteArray &path = qgetenv("XDG_RUNTIME_DIR"); if (!path.isEmpty()) return QString::fromLocal8Bit(path); return QStringLiteral("/run/user/") + QString::number(getuid()); } case XDG::StateHome: { const QByteArray &path = qgetenv("XDG_STATE_HOME"); if (!path.isEmpty()) return QString::fromLocal8Bit(path); #ifdef Q_OS_LINUX return homePath() + QStringLiteral("/.local/state"); #else // TODO: handle it on mac return QString(); #endif } } return QString(); } QString DStandardPaths::path(DStandardPaths::DSG type) { const auto list = paths(type); return list.isEmpty() ? nullptr : list.first(); } QStringList DStandardPaths::paths(DSG type) { QStringList paths; if (type == DSG::DataDir) { const QByteArray &path = qgetenv("DSG_DATA_DIRS"); if (path.isEmpty()) { return {QLatin1String(PREFIX"/share/dsg")}; } const auto list = path.split(':'); paths.reserve(list.size()); for (const auto &i : list) paths.push_back(QString::fromLocal8Bit(i)); } else if (type == DSG::AppData) { const QByteArray &path = qgetenv("DSG_APP_DATA"); //TODO 应用数据目录规范:`/persistent/appdata/{appid}`, now `appid` is not captured. paths.push_back(QString::fromLocal8Bit(path)); } return paths; } QString DStandardPaths::filePath(DStandardPaths::XDG type, QString fileName) { const QString &dir = path(type); if (dir.isEmpty()) return QString(); return dir + QLatin1Char('/') + fileName; } QString DStandardPaths::filePath(DStandardPaths::DSG type, const QString fileName) { const QString &dir = path(type); if (dir.isEmpty()) return QString(); return dir + QLatin1Char('/') + fileName; } QString DStandardPaths::homePath(const uint uid) { struct passwd *pw = getpwuid(uid); if (!pw) return QString(); const char *homedir = pw->pw_dir; return QString::fromLocal8Bit(homedir); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dtrashmanager_dummy.cpp000066400000000000000000000061021476226660600227710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtrashmanager.h" #include "DObjectPrivate" #include #include #include #include #include DCORE_BEGIN_NAMESPACE class DTrashManager_ : public DTrashManager {}; Q_GLOBAL_STATIC(DTrashManager_, globalTrashManager) static QString getNotExistsFileName(const QString &fileName, const QString &targetPath) { QByteArray name = fileName.toUtf8(); int index = name.lastIndexOf('.'); QByteArray suffix; if (index >= 0) { suffix = name.mid(index); } if (suffix.size() > 200) { suffix = suffix.left(200); } name.chop(suffix.size()); name = name.left(200 - suffix.size()); while (QFile::exists(targetPath + "/" + name + suffix)) { name = QCryptographicHash::hash(name, QCryptographicHash::Md5).toHex(); } return QString::fromUtf8(name + suffix); } static bool renameFile(const QFileInfo &fileInfo, const QString &target, QString *errorString = NULL) { if (fileInfo.isFile() || fileInfo.isSymLink()) { QFile file(fileInfo.filePath()); if (!file.rename(target)) { if (errorString) { *errorString = file.errorString(); } return false; } return true; } else { QDirIterator iterator(fileInfo.filePath(), QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); while (iterator.hasNext()) { iterator.next(); const QString newFile = iterator.filePath().replace(0, fileInfo.filePath().length(), target); if (!QDir().mkpath(QFileInfo(newFile).path())) { if (errorString) { *errorString = QString("Make the %1 path is failed").arg(QFileInfo(newFile).path()); } return false; } if (!renameFile(iterator.fileInfo(), newFile, errorString)) { return false; } } if (!QDir().rmdir(fileInfo.filePath())) { if (errorString) { *errorString = QString("Cannot remove the %1 dir").arg(fileInfo.filePath()); } return false; } } return true; } class DTrashManagerPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: DTrashManagerPrivate(DTrashManager *q_ptr) : DObjectPrivate(q_ptr) {} D_DECLARE_PUBLIC(DTrashManager) }; DTrashManager *DTrashManager::instance() { return globalTrashManager; } bool DTrashManager::trashIsEmpty() const { return false; } bool DTrashManager::cleanTrash() { return false; } bool DTrashManager::moveToTrash(const QString &filePath, bool followSymlink) { return false; } DTrashManager::DTrashManager() : QObject() , DObject(*new DTrashManagerPrivate(this)) { } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/dtrashmanager_linux.cpp000066400000000000000000000146751476226660600230130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtrashmanager.h" #include "dstandardpaths.h" #include "base/private/dobject_p.h" #include #include #include #include #include #define TRASH_PATH \ DStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/Trash" #define TRASH_INFO_PATH TRASH_PATH"/info" #define TRASH_FILES_PATH TRASH_PATH"/files" DCORE_BEGIN_NAMESPACE class DTrashManager_ : public DTrashManager {}; Q_GLOBAL_STATIC(DTrashManager_, globalTrashManager) static QString getNotExistsFileName(const QString &fileName, const QString &targetPath) { QByteArray name = fileName.toUtf8(); int index = name.lastIndexOf('.'); QByteArray suffix; if (index >= 0) { suffix = name.mid(index); } if (suffix.size() > 200) { suffix = suffix.left(200); } name.chop(suffix.size()); name = name.left(200 - suffix.size()); while (QFile::exists(targetPath + "/" + name + suffix)) { name = QCryptographicHash::hash(name, QCryptographicHash::Md5).toHex(); } return QString::fromUtf8(name + suffix); } static bool writeTrashInfo(const QString &fileBaseName, const QString &sourceFilePath, const QDateTime &datetime, QString *errorString = NULL) { QFile metadata(TRASH_INFO_PATH"/" + fileBaseName + ".trashinfo"); if (metadata.exists()) { if (errorString) { *errorString = QString("The %1 file is exists").arg(metadata.fileName()); } return false; } if (!metadata.open(QIODevice::WriteOnly)) { if (errorString) { *errorString = metadata.errorString(); } return false; } QByteArray data; data.append("[Trash Info]\n"); data.append("Path=").append(sourceFilePath.toUtf8().toPercentEncoding("/")).append("\n"); data.append("DeletionDate=").append(datetime.toString(Qt::ISODate).toLatin1()).append("\n"); qint64 size = metadata.write(data); metadata.close(); if (size <= 0) { if (errorString) { *errorString = metadata.errorString(); } return false; } return true; } static bool renameFile(const QFileInfo &fileInfo, const QString &target, QString *errorString = NULL) { if (fileInfo.isFile() || fileInfo.isSymLink()) { QFile file(fileInfo.filePath()); if (!file.rename(target)) { if (errorString) { *errorString = file.errorString(); } return false; } return true; } else { QDirIterator iterator(fileInfo.filePath(), QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); while (iterator.hasNext()) { iterator.next(); const QString newFile = iterator.filePath().replace(0, fileInfo.filePath().length(), target); if (!QDir().mkpath(QFileInfo(newFile).path())) { if (errorString) { *errorString = QString("Make the %1 path is failed").arg(QFileInfo(newFile).path()); } return false; } if (!renameFile(iterator.fileInfo(), newFile, errorString)) { return false; } } if (!QDir().rmdir(fileInfo.filePath())) { if (errorString) { *errorString = QString("Cannot remove the %1 dir").arg(fileInfo.filePath()); } return false; } } return true; } class DTrashManagerPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: DTrashManagerPrivate(DTrashManager *q_ptr) : DObjectPrivate(q_ptr) {} static bool removeFileOrDir(const QString &path); static bool removeFromIterator(QDirIterator &iter); D_DECLARE_PUBLIC(DTrashManager) }; DTrashManager *DTrashManager::instance() { return globalTrashManager; } bool DTrashManager::trashIsEmpty() const { QDirIterator iterator(TRASH_INFO_PATH, // QStringList() << "*.trashinfo", QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); return !iterator.hasNext(); } bool DTrashManager::cleanTrash() { QDirIterator iterator_info(TRASH_INFO_PATH, QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); QDirIterator iterator_files(TRASH_FILES_PATH, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDirIterator::Subdirectories); return DTrashManagerPrivate::removeFromIterator(iterator_info) && DTrashManagerPrivate::removeFromIterator(iterator_files); } bool DTrashManager::moveToTrash(const QString &filePath, bool followSymlink) { QFileInfo fileInfo(filePath); if (!fileInfo.exists() && (followSymlink || !fileInfo.isSymLink())) { return false; } QDir trashDir(TRASH_FILES_PATH); QStorageInfo storageInfo(fileInfo.filePath()); QStorageInfo trashStorageInfo(trashDir); if (storageInfo != trashStorageInfo) { return false; } if (!trashDir.mkpath(TRASH_INFO_PATH)) { return false; } if (!trashDir.mkpath(TRASH_FILES_PATH)) { return false; } if (followSymlink && fileInfo.isSymLink()) { fileInfo.setFile(fileInfo.symLinkTarget()); } const QString &fileName = getNotExistsFileName(fileInfo.fileName(), TRASH_FILES_PATH); if (!writeTrashInfo(fileName, fileInfo.filePath(), QDateTime::currentDateTime())) { return false; } const QString &newFilePath = TRASH_FILES_PATH"/" + fileName; return renameFile(fileInfo, newFilePath); } DTrashManager::DTrashManager() : QObject() , DObject(*new DTrashManagerPrivate(this)) { } bool DTrashManagerPrivate::removeFileOrDir(const QString &path) { QFileInfo fileInfo(path); if (fileInfo.isDir() && !fileInfo.isSymLink()) { QDir dir(path); return dir.removeRecursively(); } else { return QFile::remove(path); } } bool DTrashManagerPrivate::removeFromIterator(QDirIterator &iter) { bool ok = true; while (iter.hasNext()) { QString nextPath = iter.next(); // qDebug() << iter.fileName() << iterator_info.filePath(); if (!DTrashManagerPrivate::removeFileOrDir(nextPath)) { ok = false; } } return ok; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/filesystem/filesystem.cmake000066400000000000000000000044201476226660600214210ustar00rootroot00000000000000if(APPLE) set(FILESYSTEM_SOURCE ${CMAKE_CURRENT_LIST_DIR}/private/dbasefilewatcher_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dfilesystemwatcher_linux_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dcapfsfileengine_p.h ${CMAKE_CURRENT_LIST_DIR}/dbasefilewatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilesystemwatcher_dummy.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilewatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilewatchermanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dpathbuf.cpp ${CMAKE_CURRENT_LIST_DIR}/dtrashmanager_dummy.cpp ${CMAKE_CURRENT_LIST_DIR}/dstandardpaths.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapfile.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapfsfileengine.cpp ) elseif(WIN32) set(FILESYSTEM_SOURCE ${CMAKE_CURRENT_LIST_DIR}/private/dbasefilewatcher_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dfilesystemwatcher_linux_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dcapfsfileengine_p.h ${CMAKE_CURRENT_LIST_DIR}/dbasefilewatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilesystemwatcher_win.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilewatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilewatchermanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dpathbuf.cpp ${CMAKE_CURRENT_LIST_DIR}/dtrashmanager_dummy.cpp ${CMAKE_CURRENT_LIST_DIR}/dstandardpaths.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapfile.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapfsfileengine.cpp ) else() set(FILESYSTEM_SOURCE ${CMAKE_CURRENT_LIST_DIR}/private/dbasefilewatcher_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dfilesystemwatcher_linux_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dcapfsfileengine_p.h ${CMAKE_CURRENT_LIST_DIR}/dbasefilewatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilesystemwatcher_linux.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilewatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dfilewatchermanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dpathbuf.cpp ${CMAKE_CURRENT_LIST_DIR}/dtrashmanager_linux.cpp ${CMAKE_CURRENT_LIST_DIR}/dstandardpaths.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapfile.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dcapfsfileengine.cpp ) endif() file(GLOB FILESYSTEM_HEAD ${CMAKE_CURRENT_LIST_DIR}/../../include/filesystem/* ) set(filesystem_SRCS ${FILESYSTEM_HEAD} ${FILESYSTEM_SOURCE} ) dtkcore-5.7.12/src/filesystem/private/000077500000000000000000000000001476226660600177055ustar00rootroot00000000000000dtkcore-5.7.12/src/filesystem/private/dbasefilewatcher_p.h000066400000000000000000000012131476226660600236660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DBASEFILEWATCHER_P_H #define DBASEFILEWATCHER_P_H #include "base/private/dobject_p.h" #include DCORE_BEGIN_NAMESPACE class DBaseFileWatcher; class DBaseFileWatcherPrivate : public DObjectPrivate { public: DBaseFileWatcherPrivate(DBaseFileWatcher *qq); virtual bool start() = 0; virtual bool stop() = 0; QUrl url; bool started = false; static QList watcherList; D_DECLARE_PUBLIC(DBaseFileWatcher) }; DCORE_END_NAMESPACE #endif // DBASEFILEWATCHER_P_H dtkcore-5.7.12/src/filesystem/private/dcapfsfileengine_p.h000066400000000000000000000046331476226660600236710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DCAPFSFILEENGINE_P_H #define DCAPFSFILEENGINE_P_H #include #include DCORE_BEGIN_NAMESPACE class DCapFSFileEngineHandler : public QAbstractFileEngineHandler { public: #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) std::unique_ptr create(const QString &fileName) const override; #else QAbstractFileEngine *create(const QString &fileName) const override; #endif }; class DCapFSFileEnginePrivate; class DCapFSFileEngine : public QFSFileEngine, public DObject { D_DECLARE_PRIVATE(DCapFSFileEngine); public: DCapFSFileEngine(const QString &file); ~DCapFSFileEngine() override; #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool open(QIODevice::OpenMode openMode, std::optional permissions = std::nullopt) override; #else bool open(QIODevice::OpenMode openMode) override; #endif bool remove() override; bool copy(const QString &newName) override; bool rename(const QString &newName) override; bool renameOverwrite(const QString &newName) override; bool link(const QString &newName) override; #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) bool mkdir(const QString &dirName, bool createParentDirectories, std::optional permissions = std::nullopt) const override; #else bool mkdir(const QString &dirName, bool createParentDirectories) const override; #endif bool rmdir(const QString &dirName, bool recurseParentDirectories) const override; FileFlags fileFlags(FileFlags type) const override; bool cloneTo(QAbstractFileEngine *target) override; bool setSize(qint64 size) override; QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override; #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override; #elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override; #else Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override; #endif bool canReadWrite(const QString &path) const; }; DCORE_END_NAMESPACE #endif // DCAPFSFILEENGINE_P_H dtkcore-5.7.12/src/filesystem/private/dfilesystemwatcher_dummy_p.h000066400000000000000000000012311476226660600255130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILESYSTEMWATCHER_WIN_P_H #define DFILESYSTEMWATCHER_WIN_P_H #include "base/private/dobject_p.h" DCORE_BEGIN_NAMESPACE class DFileSystemWatcher; class DFileSystemWatcherPrivate : public DObjectPrivate { Q_DECLARE_PUBLIC(DFileSystemWatcher) public: DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq); ~DFileSystemWatcherPrivate(); // private slots void _q_readFromInotify(); }; void DFileSystemWatcherPrivate::_q_readFromInotify() { } DCORE_END_NAMESPACE #endif // DFILESYSTEMWATCHER_WIN_P_H dtkcore-5.7.12/src/filesystem/private/dfilesystemwatcher_linux_p.h000066400000000000000000000021561476226660600255260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILESYSTEMWATCHER_P_H #define DFILESYSTEMWATCHER_P_H #include "dobject_p.h" #include #include #include DCORE_BEGIN_NAMESPACE class DFileSystemWatcher; class DFileSystemWatcherPrivate : public DObjectPrivate { Q_DECLARE_PUBLIC(DFileSystemWatcher) public: DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq); ~DFileSystemWatcherPrivate(); QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList files, directories; int inotifyFd; QHash pathToID; QMultiHash idToPath; QSocketNotifier notifier; // private slots void _q_readFromInotify(); private: void onFileChanged(const QString &path, bool removed); void onDirectoryChanged(const QString &path, bool removed); }; DCORE_END_NAMESPACE #endif // DFILESYSTEMWATCHER_P_H dtkcore-5.7.12/src/filesystem/private/dfilesystemwatcher_win_p.h000066400000000000000000000012311476226660600251550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILESYSTEMWATCHER_WIN_P_H #define DFILESYSTEMWATCHER_WIN_P_H #include "base/private/dobject_p.h" DCORE_BEGIN_NAMESPACE class DFileSystemWatcher; class DFileSystemWatcherPrivate : public DObjectPrivate { Q_DECLARE_PUBLIC(DFileSystemWatcher) public: DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq); ~DFileSystemWatcherPrivate(); // private slots void _q_readFromInotify(); }; void DFileSystemWatcherPrivate::_q_readFromInotify() { } DCORE_END_NAMESPACE #endif // DFILESYSTEMWATCHER_WIN_P_H dtkcore-5.7.12/src/filesystem/private/private.pri000066400000000000000000000003341476226660600220730ustar00rootroot00000000000000HEADERS += \ $$PWD/dbasefilewatcher_p.h \ $$PWD/dcapfsfileengine_p.h linux { HEADERS += \ $$PWD/dfilesystemwatcher_linux_p.h } else:win* { HEADERS += \ $$PWD/dfilesystemwatcher_win_p.h } dtkcore-5.7.12/src/glob.cmake000066400000000000000000000027221476226660600157770ustar00rootroot00000000000000set(OUTER_SOURCE ${CMAKE_CURRENT_LIST_DIR}/dconfig.cpp ${CMAKE_CURRENT_LIST_DIR}/dsgapplication.cpp ${CMAKE_CURRENT_LIST_DIR}/dsysinfo.cpp ${CMAKE_CURRENT_LIST_DIR}/dlicenseinfo.cpp ${CMAKE_CURRENT_LIST_DIR}/dsecurestring.cpp ${CMAKE_CURRENT_LIST_DIR}/ddesktopentry.cpp ) if (NOT DTK_VERSION_MAJOR) list(APPEND OUTER_SOURCE ${CMAKE_CURRENT_LIST_DIR}/dtkcore_global.cpp) endif() set(OUTER_HEADER ${CMAKE_CURRENT_LIST_DIR}/../include/global/dtkcore_global.h ${CMAKE_CURRENT_LIST_DIR}/../include/global/dconfig.h ${CMAKE_CURRENT_LIST_DIR}/../include/global/dsgapplication.h ${CMAKE_CURRENT_LIST_DIR}/../include/global/dsysinfo.h ${CMAKE_CURRENT_LIST_DIR}/../include/global/dlicenseinfo.h ${CMAKE_CURRENT_LIST_DIR}/../include/global/dsecurestring.h ${CMAKE_CURRENT_LIST_DIR}/../include/global/ddesktopentry.h ) if(LINUX) if(DEFINED D_DSG_APP_DATA_FALLBACK) add_definitions(-DD_DSG_APP_DATA_FALLBACK="${D_DSG_APP_DATA_FALLBACK}") endif() list(APPEND OUTER_SOURCE ${CMAKE_CURRENT_LIST_DIR}/dconfigfile.cpp ) list(APPEND OUTER_HEADER ${CMAKE_CURRENT_LIST_DIR}/../include/global/dconfigfile.h ) # generic dbus interfaces if(NOT DEFINED DTK_DISABLE_DBUS_CONFIG) include(${CMAKE_CURRENT_LIST_DIR}/dbus/dbus.cmake) list(APPEND glob_SRC ${dbus_SRCS}) else() add_definitions(-DD_DISABLE_DBUS_CONFIG) endif() else() add_definitions(-DD_DISABLE_DCONFIG) endif() list(APPEND glob_SRC ${OUTER_HEADER} ${OUTER_SOURCE} ) dtkcore-5.7.12/src/log/000077500000000000000000000000001476226660600146305ustar00rootroot00000000000000dtkcore-5.7.12/src/log/LogManager.cpp000066400000000000000000000206211476226660600173510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "LogManager.h" #include #include #include #include #include #include "dstandardpaths.h" #include "dconfig_org_deepin_dtk_preference.hpp" DCORE_BEGIN_NAMESPACE #define RULES_KEY ("rules") // Courtesy qstandardpaths_unix.cpp static void appendOrganizationAndApp(QString &path) { #ifndef QT_BOOTSTRAPPED const QString org = QCoreApplication::organizationName(); if (!org.isEmpty()) path += QLatin1Char('/') + org; const QString appName = QCoreApplication::applicationName(); if (!appName.isEmpty()) path += QLatin1Char('/') + appName; #else Q_UNUSED(path); #endif } #define DEFAULT_FMT "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}" class DLogManagerPrivate { public: explicit DLogManagerPrivate(DLogManager *q) : m_format(DEFAULT_FMT) , q_ptr(q) { } dconfig_org_deepin_dtk_preference *createDConfig(const QString &appId); void initLoggingRules(); void updateLoggingRules(); QString m_format; QString m_logPath; ConsoleAppender* m_consoleAppender = nullptr; RollingFileAppender* m_rollingFileAppender = nullptr; JournalAppender* m_journalAppender = nullptr; QScopedPointer m_dsgConfig; QScopedPointer m_fallbackConfig; DLogManager *q_ptr = nullptr; Q_DECLARE_PUBLIC(DLogManager) }; dconfig_org_deepin_dtk_preference *DLogManagerPrivate::createDConfig(const QString &appId) { if (appId.isEmpty()) return nullptr; auto config = dconfig_org_deepin_dtk_preference::create(appId); QObject::connect(config, &dconfig_org_deepin_dtk_preference::rulesChanged, config, [this](){ updateLoggingRules(); }); return config; } void DLogManagerPrivate::initLoggingRules() { if (qEnvironmentVariableIsSet("DTK_DISABLED_LOGGING_RULES")) return; // 1. 未指定 fallbackId 时,以 dsgAppId 为准 QString dsgAppId = DSGApplication::id(); m_dsgConfig.reset(createDConfig(dsgAppId)); if (m_dsgConfig) { QObject::connect(m_dsgConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeSucceed, m_dsgConfig.data(), [this](){ updateLoggingRules(); }); QObject::connect(m_dsgConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeFailed, m_dsgConfig.data(), [this, dsgAppId] { m_dsgConfig.reset(); qWarning() << "Logging rules config is invalid, please check `appId` [" << dsgAppId << "]arg is correct"; }); } QString fallbackId = qgetenv("DTK_LOGGING_FALLBACK_APPID"); // 2. fallbackId 和 dsgAppId 非空且不等时,都创建和监听变化 if (!fallbackId.isEmpty() && fallbackId != dsgAppId) m_fallbackConfig.reset(createDConfig(fallbackId)); // 3. 默认值和非默认值时,非默认值优先 if (m_fallbackConfig) { QObject::connect(m_fallbackConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeSucceed, m_fallbackConfig.data(), [this](){ updateLoggingRules(); }); QObject::connect(m_fallbackConfig.data(), &dconfig_org_deepin_dtk_preference::configInitializeFailed, m_fallbackConfig.data(), [this, fallbackId] { m_fallbackConfig.reset(); qWarning() << "Logging rules config is invalid, please check `appId` [" << fallbackId << "]arg is correct"; }); } } void DLogManagerPrivate::updateLoggingRules() { QVariant var; // 4. 优先看 dsgConfig 是否默认值,其次 fallback 是否默认值 if (m_dsgConfig && m_dsgConfig->isInitializeSucceed() && !m_dsgConfig->rulesIsDefaultValue()) { var = m_dsgConfig->rules(); } else if (m_fallbackConfig && m_dsgConfig->isInitializeSucceed() && !m_fallbackConfig->rulesIsDefaultValue()) { var = m_fallbackConfig->rules(); } else if (m_dsgConfig && m_dsgConfig->isInitializeSucceed()) { var = m_dsgConfig->rules(); } if (var.isValid()) QLoggingCategory::setFilterRules(var.toString().replace(";", "\n")); } /*! @~english \class Dtk::Core::DLogManager \inmodule dtkcore \brief DLogManager is the deepin user application log manager. */ DLogManager::DLogManager() :d_ptr(new DLogManagerPrivate(this)) { d_ptr->initLoggingRules(); } void DLogManager::initConsoleAppender(){ Q_D(DLogManager); d->m_consoleAppender = new ConsoleAppender; d->m_consoleAppender->setFormat(d->m_format); dlogger->registerAppender(d->m_consoleAppender); } void DLogManager::initRollingFileAppender(){ Q_D(DLogManager); d->m_rollingFileAppender = new RollingFileAppender(getlogFilePath()); d->m_rollingFileAppender->setFormat(d->m_format); d->m_rollingFileAppender->setLogFilesLimit(5); d->m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover); dlogger->registerAppender(d->m_rollingFileAppender); } void DLogManager::initJournalAppender() { #if (defined BUILD_WITH_SYSTEMD && defined Q_OS_LINUX) Q_D(DLogManager); d->m_journalAppender = new JournalAppender(); dlogger->registerAppender(d->m_journalAppender); #else qWarning() << "BUILD_WITH_SYSTEMD not defined or OS not support!!"; #endif } /*! @~english \brief Registers the appender to write the log records to the Console. \sa registerFileAppender */ void DLogManager::registerConsoleAppender(){ DLogManager::instance()->initConsoleAppender(); } /*! @~english \brief Registers the appender to write the log records to the file. \sa getlogFilePath \sa registerConsoleAppender */ void DLogManager::registerFileAppender() { DLogManager::instance()->initRollingFileAppender(); } void DLogManager::registerJournalAppender() { DLogManager::instance()->initJournalAppender(); } /*! @~english \brief Return the path file log storage. \brief DLogManager::getlogFilePath Get the log file path \brief The default log path is ~/.cache//.log \brief If the environment variable $HOME cannot be acquired, DLogManager will not log anything \sa registerFileAppender */ QString DLogManager::getlogFilePath() { //No longer set the default log path (and mkdir) when constructing now, instead set the default value if it's empty when getlogFilePath is called. //Fix the problem that the log file is still created in the default path when the log path is set manually. if (DLogManager::instance()->d_func()->m_logPath.isEmpty()) { if (DStandardPaths::homePath().isEmpty()) { qWarning() << "Unable to locate the cache directory, cannot acquire home directory, and the log will not be written to file.."; return QString(); } QString cachePath(DStandardPaths::path(DStandardPaths::XDG::CacheHome)); appendOrganizationAndApp(cachePath); if (!QDir(cachePath).exists()) { QDir(cachePath).mkpath(cachePath); } instance()->d_func()->m_logPath = instance()->joinPath(cachePath, QString("%1.log").arg(qApp->applicationName())); } return QDir::toNativeSeparators(DLogManager::instance()->d_func()->m_logPath); } /*! @~english \brief DLogManager::setlogFilePath Set the log file path \a logFilePath Log file path \brief If the file path set is not the file path, nothing will do, and an output warning */ void DLogManager::setlogFilePath(const QString &logFilePath) { QFileInfo info(logFilePath); if (info.exists() && !info.isFile()) qWarning() << "invalid file path:" << logFilePath << " is not a file"; else DLogManager::instance()->d_func()->m_logPath = logFilePath; } void DLogManager::setLogFormat(const QString &format) { //m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"; DLogManager::instance()->d_func()->m_format = format; } QString DLogManager::joinPath(const QString &path, const QString &fileName){ QString separator(QDir::separator()); return QString("%1%2%3").arg(path, separator, fileName); } DLogManager::~DLogManager() { } DCORE_END_NAMESPACE dtkcore-5.7.12/src/log/dconfig_org_deepin_dtk_preference.hpp000066400000000000000000000567221476226660600242210ustar00rootroot00000000000000/** * This file is generated by dconfig2cpp. * Command line arguments: /home/zccrs/projects/dtkcore/build/unknown-Debug/tools/dconfig2cpp/dconfig2cpp /home/zccrs/projects/dtkcommon/configs/org.deepin.dtk.preference.json * Generation time: 2025-03-06T10:40:41 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. * If you need to change the content, please modify the dconfig2cpp tool. */ #ifndef DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H #define DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #endif #include class dconfig_org_deepin_dtk_preference : public QObject { Q_OBJECT Q_PROPERTY(bool autoDisplayFeature READ autoDisplayFeature WRITE setAutoDisplayFeature NOTIFY autoDisplayFeatureChanged RESET resetAutoDisplayFeature) Q_PROPERTY(bool featureUpdated READ featureUpdated WRITE setFeatureUpdated NOTIFY featureUpdatedChanged RESET resetFeatureUpdated) Q_PROPERTY(bool keyboardsearchDisabled READ keyboardsearchDisabled WRITE setKeyboardsearchDisabled NOTIFY keyboardsearchDisabledChanged RESET resetKeyboardsearchDisabled) Q_PROPERTY(QString rules READ rules WRITE setRules NOTIFY rulesChanged RESET resetRules) Q_PROPERTY(qlonglong themeType READ themeType WRITE setThemeType NOTIFY themeTypeChanged RESET resetThemeType) Q_PROPERTY(qlonglong titlebarHeight READ titlebarHeight WRITE setTitlebarHeight NOTIFY titlebarHeightChanged RESET resetTitlebarHeight) Q_PROPERTY(bool underlineShortcut READ underlineShortcut WRITE setUnderlineShortcut NOTIFY underlineShortcutChanged RESET resetUnderlineShortcut) Q_CLASSINFO("DConfigKeyList", "autoDisplayFeature;featureUpdated;keyboardsearchDisabled;rules;themeType;titlebarHeight;underlineShortcut") Q_CLASSINFO("DConfigFileName", "org.deepin.dtk.preference") Q_CLASSINFO("DConfigFileVersion", "1.0") public: explicit dconfig_org_deepin_dtk_preference(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId, const QString &subpath, QObject *parent) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=, this]() { DTK_CORE_NAMESPACE::DConfig *config = nullptr; if (backend) { if (appId.isNull()) { config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); } else { config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); } } else { if (appId.isNull()) { config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); } else { config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); } } if (!config) { qWarning() << QLatin1String("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initializeInConfigThread(config); worker->deleteLater(); }); } static dconfig_org_deepin_dtk_preference* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) { return new dconfig_org_deepin_dtk_preference(thread, nullptr, QStringLiteral(u"\u006f\u0072\u0067\u002e\u0064\u0065\u0065\u0070\u0069\u006e\u002e\u0064\u0074\u006b\u002e\u0070\u0072\u0065\u0066\u0065\u0072\u0065\u006e\u0063\u0065"), appId, subpath, parent); } static dconfig_org_deepin_dtk_preference* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) { return new dconfig_org_deepin_dtk_preference(thread, backend, QStringLiteral(u"\u006f\u0072\u0067\u002e\u0064\u0065\u0065\u0070\u0069\u006e\u002e\u0064\u0074\u006b\u002e\u0070\u0072\u0065\u0066\u0065\u0072\u0065\u006e\u0063\u0065"), appId, subpath, parent); } static dconfig_org_deepin_dtk_preference* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) { return new dconfig_org_deepin_dtk_preference(thread, nullptr, name, appId, subpath, parent); } static dconfig_org_deepin_dtk_preference* createByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) { return new dconfig_org_deepin_dtk_preference(thread, backend, name, appId, subpath, parent); } ~dconfig_org_deepin_dtk_preference() { if (m_config.loadRelaxed()) { m_config.loadRelaxed()->deleteLater(); } } Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { return m_config.loadRelaxed(); } Q_INVOKABLE bool isInitializeSucceed() const { return m_status.loadRelaxed() == static_cast(Status::Succeed); } Q_INVOKABLE bool isInitializeFailed() const { return m_status.loadRelaxed() == static_cast(Status::Failed); } Q_INVOKABLE bool isInitializing() const { return m_status.loadRelaxed() == static_cast(Status::Invalid); } Q_INVOKABLE QStringList keyList() const { return { QStringLiteral("autoDisplayFeature"), QStringLiteral("featureUpdated"), QStringLiteral("keyboardsearchDisabled"), QStringLiteral("rules"), QStringLiteral("themeType"), QStringLiteral("titlebarHeight"), QStringLiteral("underlineShortcut")}; } Q_INVOKABLE bool isDefaultValue(const QString &key) const { if (key == QStringLiteral("autoDisplayFeature")) return autoDisplayFeatureIsDefaultValue(); if (key == QStringLiteral("featureUpdated")) return featureUpdatedIsDefaultValue(); if (key == QStringLiteral("keyboardsearchDisabled")) return keyboardsearchDisabledIsDefaultValue(); if (key == QStringLiteral("rules")) return rulesIsDefaultValue(); if (key == QStringLiteral("themeType")) return themeTypeIsDefaultValue(); if (key == QStringLiteral("titlebarHeight")) return titlebarHeightIsDefaultValue(); if (key == QStringLiteral("underlineShortcut")) return underlineShortcutIsDefaultValue(); return false; } bool autoDisplayFeature() const { return p_autoDisplayFeature; } void setAutoDisplayFeature(const bool &value) { auto oldValue = p_autoDisplayFeature; p_autoDisplayFeature = value; markPropertySet(0); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("autoDisplayFeature"), value); }); } if (p_autoDisplayFeature != oldValue) { Q_EMIT autoDisplayFeatureChanged(); Q_EMIT valueChanged(QStringLiteral("autoDisplayFeature"), value); } } void resetAutoDisplayFeature() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("autoDisplayFeature")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableAutoDisplayFeature() { return QBindable(this, QStringLiteral("autoDisplayFeature")); } #endif Q_INVOKABLE bool autoDisplayFeatureIsDefaultValue() const { return !testPropertySet(0); } bool featureUpdated() const { return p_featureUpdated; } void setFeatureUpdated(const bool &value) { auto oldValue = p_featureUpdated; p_featureUpdated = value; markPropertySet(1); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("featureUpdated"), value); }); } if (p_featureUpdated != oldValue) { Q_EMIT featureUpdatedChanged(); Q_EMIT valueChanged(QStringLiteral("featureUpdated"), value); } } void resetFeatureUpdated() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("featureUpdated")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableFeatureUpdated() { return QBindable(this, QStringLiteral("featureUpdated")); } #endif Q_INVOKABLE bool featureUpdatedIsDefaultValue() const { return !testPropertySet(1); } bool keyboardsearchDisabled() const { return p_keyboardsearchDisabled; } void setKeyboardsearchDisabled(const bool &value) { auto oldValue = p_keyboardsearchDisabled; p_keyboardsearchDisabled = value; markPropertySet(2); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("keyboardsearchDisabled"), value); }); } if (p_keyboardsearchDisabled != oldValue) { Q_EMIT keyboardsearchDisabledChanged(); Q_EMIT valueChanged(QStringLiteral("keyboardsearchDisabled"), value); } } void resetKeyboardsearchDisabled() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("keyboardsearchDisabled")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableKeyboardsearchDisabled() { return QBindable(this, QStringLiteral("keyboardsearchDisabled")); } #endif Q_INVOKABLE bool keyboardsearchDisabledIsDefaultValue() const { return !testPropertySet(2); } QString rules() const { return p_rules; } void setRules(const QString &value) { auto oldValue = p_rules; p_rules = value; markPropertySet(3); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("rules"), value); }); } if (p_rules != oldValue) { Q_EMIT rulesChanged(); Q_EMIT valueChanged(QStringLiteral("rules"), value); } } void resetRules() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("rules")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableRules() { return QBindable(this, QStringLiteral("rules")); } #endif Q_INVOKABLE bool rulesIsDefaultValue() const { return !testPropertySet(3); } qlonglong themeType() const { return p_themeType; } void setThemeType(const qlonglong &value) { auto oldValue = p_themeType; p_themeType = value; markPropertySet(4); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("themeType"), value); }); } if (p_themeType != oldValue) { Q_EMIT themeTypeChanged(); Q_EMIT valueChanged(QStringLiteral("themeType"), value); } } void resetThemeType() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("themeType")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableThemeType() { return QBindable(this, QStringLiteral("themeType")); } #endif Q_INVOKABLE bool themeTypeIsDefaultValue() const { return !testPropertySet(4); } qlonglong titlebarHeight() const { return p_titlebarHeight; } void setTitlebarHeight(const qlonglong &value) { auto oldValue = p_titlebarHeight; p_titlebarHeight = value; markPropertySet(5); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("titlebarHeight"), value); }); } if (p_titlebarHeight != oldValue) { Q_EMIT titlebarHeightChanged(); Q_EMIT valueChanged(QStringLiteral("titlebarHeight"), value); } } void resetTitlebarHeight() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("titlebarHeight")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableTitlebarHeight() { return QBindable(this, QStringLiteral("titlebarHeight")); } #endif Q_INVOKABLE bool titlebarHeightIsDefaultValue() const { return !testPropertySet(5); } bool underlineShortcut() const { return p_underlineShortcut; } void setUnderlineShortcut(const bool &value) { auto oldValue = p_underlineShortcut; p_underlineShortcut = value; markPropertySet(6); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("underlineShortcut"), value); }); } if (p_underlineShortcut != oldValue) { Q_EMIT underlineShortcutChanged(); Q_EMIT valueChanged(QStringLiteral("underlineShortcut"), value); } } void resetUnderlineShortcut() { if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this]() { m_config.loadRelaxed()->reset(QStringLiteral("underlineShortcut")); }); } } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QBindable bindableUnderlineShortcut() { return QBindable(this, QStringLiteral("underlineShortcut")); } #endif Q_INVOKABLE bool underlineShortcutIsDefaultValue() const { return !testPropertySet(6); } Q_SIGNALS: void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config); void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config); void valueChanged(const QString &key, const QVariant &value); void autoDisplayFeatureChanged(); void featureUpdatedChanged(); void keyboardsearchDisabledChanged(); void rulesChanged(); void themeTypeChanged(); void titlebarHeightChanged(); void underlineShortcutChanged(); private: void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) { Q_ASSERT(!m_config.loadRelaxed()); m_config.storeRelaxed(config); if (!config->isValid()) { m_status.storeRelaxed(static_cast(Status::Failed)); Q_EMIT configInitializeFailed(config); return; } if (testPropertySet(0)) { config->setValue(QStringLiteral("autoDisplayFeature"), QVariant::fromValue(p_autoDisplayFeature)); } else { updateValue(QStringLiteral("autoDisplayFeature"), QVariant::fromValue(p_autoDisplayFeature)); } if (testPropertySet(1)) { config->setValue(QStringLiteral("featureUpdated"), QVariant::fromValue(p_featureUpdated)); } else { updateValue(QStringLiteral("featureUpdated"), QVariant::fromValue(p_featureUpdated)); } if (testPropertySet(2)) { config->setValue(QStringLiteral("keyboardsearchDisabled"), QVariant::fromValue(p_keyboardsearchDisabled)); } else { updateValue(QStringLiteral("keyboardsearchDisabled"), QVariant::fromValue(p_keyboardsearchDisabled)); } if (testPropertySet(3)) { config->setValue(QStringLiteral("rules"), QVariant::fromValue(p_rules)); } else { updateValue(QStringLiteral("rules"), QVariant::fromValue(p_rules)); } if (testPropertySet(4)) { config->setValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); } else { updateValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); } if (testPropertySet(5)) { config->setValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); } else { updateValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); } if (testPropertySet(6)) { config->setValue(QStringLiteral("underlineShortcut"), QVariant::fromValue(p_underlineShortcut)); } else { updateValue(QStringLiteral("underlineShortcut"), QVariant::fromValue(p_underlineShortcut)); } connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { updateValue(key); }, Qt::DirectConnection); m_status.storeRelaxed(static_cast(Status::Succeed)); Q_EMIT configInitializeSucceed(config); } void updateValue(const QString &key, const QVariant &fallback = QVariant()) { Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); const QVariant &value = m_config.loadRelaxed()->value(key, fallback); if (key == QStringLiteral("autoDisplayFeature")) { markPropertySet(0, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_autoDisplayFeature != newValue) { p_autoDisplayFeature = newValue; Q_EMIT autoDisplayFeatureChanged(); Q_EMIT valueChanged(key, value); } }); return; } if (key == QStringLiteral("featureUpdated")) { markPropertySet(1, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_featureUpdated != newValue) { p_featureUpdated = newValue; Q_EMIT featureUpdatedChanged(); Q_EMIT valueChanged(key, value); } }); return; } if (key == QStringLiteral("keyboardsearchDisabled")) { markPropertySet(2, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_keyboardsearchDisabled != newValue) { p_keyboardsearchDisabled = newValue; Q_EMIT keyboardsearchDisabledChanged(); Q_EMIT valueChanged(key, value); } }); return; } if (key == QStringLiteral("rules")) { markPropertySet(3, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_rules != newValue) { p_rules = newValue; Q_EMIT rulesChanged(); Q_EMIT valueChanged(key, value); } }); return; } if (key == QStringLiteral("themeType")) { markPropertySet(4, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_themeType != newValue) { p_themeType = newValue; Q_EMIT themeTypeChanged(); Q_EMIT valueChanged(key, value); } }); return; } if (key == QStringLiteral("titlebarHeight")) { markPropertySet(5, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_titlebarHeight != newValue) { p_titlebarHeight = newValue; Q_EMIT titlebarHeightChanged(); Q_EMIT valueChanged(key, value); } }); return; } if (key == QStringLiteral("underlineShortcut")) { markPropertySet(6, !m_config.loadRelaxed()->isDefaultValue(key)); auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue, key, value]() { Q_ASSERT(QThread::currentThread() == this->thread()); if (p_underlineShortcut != newValue) { p_underlineShortcut = newValue; Q_EMIT underlineShortcutChanged(); Q_EMIT valueChanged(key, value); } }); return; } } inline void markPropertySet(const int index, bool on = true) { if (index < 32) { if (on) m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); else m_propertySetStatus0.fetchAndAndOrdered(1 << (index - 0)); return; } Q_UNREACHABLE(); } inline bool testPropertySet(const int index) const { if (index < 32) { return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); } Q_UNREACHABLE(); } QAtomicPointer m_config = nullptr; public: enum class Status { Invalid = 0, Succeed = 1, Failed = 2 }; private: QAtomicInteger m_status = static_cast(Status::Invalid); bool p_autoDisplayFeature { false }; bool p_featureUpdated { false }; bool p_keyboardsearchDisabled { false }; // Default value: "" QString p_rules { QLatin1String("") }; qlonglong p_themeType { 0 }; qlonglong p_titlebarHeight { -1 }; bool p_underlineShortcut { false }; QAtomicInteger m_propertySetStatus0 = 0; }; #endif // DCONFIG_ORG_DEEPIN_DTK_PREFERENCE_H dtkcore-5.7.12/src/log/log.cmake000066400000000000000000000003751476226660600164200ustar00rootroot00000000000000file(GLOB LOG_HEADER ${CMAKE_CURRENT_LIST_DIR}/../../include/log/LogManager.h ) set(LOG_SOURCE ${CMAKE_CURRENT_LIST_DIR}/LogManager.cpp ${CMAKE_CURRENT_LIST_DIR}/dconfig_org_deepin_dtk_preference.hpp ) set(log_SRCS ${LOG_HEADER} ${LOG_SOURCE} ) dtkcore-5.7.12/src/settings/000077500000000000000000000000001476226660600157075ustar00rootroot00000000000000dtkcore-5.7.12/src/settings/backend/000077500000000000000000000000001476226660600172765ustar00rootroot00000000000000dtkcore-5.7.12/src/settings/backend/dsettingsdconfigbackend.cpp000066400000000000000000000040551476226660600246540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "settings/backend/dsettingsdconfigbackend.h" #include #include #include DCORE_BEGIN_NAMESPACE class DSettingsDConfigBackendPrivate { public: explicit DSettingsDConfigBackendPrivate(DSettingsDConfigBackend *parent) : q_ptr(parent) {} DConfig *dConfig = nullptr; QMutex writeLock; DSettingsDConfigBackend *q_ptr; Q_DECLARE_PUBLIC(DSettingsDConfigBackend) }; /*! @~english @class Dtk::Core::DSettingsDConfigBackend \inmodule dtkcore @brief Storage DSetttings to an DConfig. */ /*! @~english @brief Save data to configure file name with DConfig. \a name configure file name. \a subpath subdirectory of configure file name. \a parent */ DSettingsDConfigBackend::DSettingsDConfigBackend(const QString &name, const QString &subpath, QObject *parent) : DSettingsBackend(parent), d_ptr(new DSettingsDConfigBackendPrivate(this)) { Q_D(DSettingsDConfigBackend); d->dConfig = new DConfig(name, subpath, this); } DSettingsDConfigBackend::~DSettingsDConfigBackend() { } /*! @~english @brief List all keys of DConfig @return */ QStringList DSettingsDConfigBackend::keys() const { Q_D(const DSettingsDConfigBackend); return d->dConfig->keyList(); } /*! @~english @brief Get value of key from DConfig \a key @return */ QVariant DSettingsDConfigBackend::getOption(const QString &key) const { Q_D(const DSettingsDConfigBackend); return d->dConfig->value(key); } /*! @~english @brief Set value of key to DConfig \a key \a value */ void DSettingsDConfigBackend::doSetOption(const QString &key, const QVariant &value) { Q_D(DSettingsDConfigBackend); d->writeLock.lock(); d->dConfig->setValue(key, value); d->writeLock.unlock(); } /*! @~english @brief Trigger DSettings to save option value to DConfig */ void DSettingsDConfigBackend::doSync() { Q_D(DSettingsDConfigBackend); // TODO } DCORE_END_NAMESPACE dtkcore-5.7.12/src/settings/backend/gsettingsbackend.cpp000066400000000000000000000065201476226660600233240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "settings/backend/gsettingsbackend.h" //#include #include #include #include #include #if QT_HAS_INCLUDE() #include #else #include #endif #include DCORE_BEGIN_NAMESPACE QString unqtifyName(const QString &name) { QString ret; for (auto p : name) { const QChar c(p); if (c.isUpper()) { ret.append("-"); ret.append(c.toLower().toLatin1()); } else { ret.append(c); } } return ret; } QString qtifyName(const QString &key) { return QString(key).replace(".", "-").replace("_", "-"); } class GSettingsBackendPrivate { public: GSettingsBackendPrivate(GSettingsBackend *parent) : q_ptr(parent) {} QGSettings *gsettings; QMap keyMap; GSettingsBackend *q_ptr; Q_DECLARE_PUBLIC(GSettingsBackend) }; /*! @~english @class Dtk::Core::GSettingsBackend \inmodule dtkcore @brief Storage backend of DSettings use gsettings. You should generate gsetting schema with /usr/lib/x86_64-linux-gnu/libdtk-$$VERSION/DCore/bin/dtk-settings. You can find this tool from libdtkcore-bin. use /usr/lib/x86_64-linux-gnu/libdtk-$$VERSION/DCore/bin/dtk-settings -h for help. */ GSettingsBackend::GSettingsBackend(DSettings *settings, QObject *parent) : DSettingsBackend(parent), d_ptr(new GSettingsBackendPrivate(this)) { Q_D(GSettingsBackend); QJsonObject settingsMeta = settings->meta(); auto gsettingsMeta = settingsMeta.value("gsettings").toObject(); auto id = gsettingsMeta.value("id").toString(); auto path = gsettingsMeta.value("path").toString(); for (QString key : settings->keys()) { auto gsettingsKey = QString(key).replace(".", "-").replace("_", "-"); d->keyMap.insert(gsettingsKey, key); } d->gsettings = new QGSettings(id.toUtf8(), path.toUtf8(), this); connect(d->gsettings, &QGSettings::changed, this, [ = ](const QString & key) { auto dk = d->keyMap.value(unqtifyName(key)); // qDebug() << "gsetting change" << key << d->gsettings->get(key); Q_EMIT optionChanged(dk, d->gsettings->get(key)); }); } GSettingsBackend::~GSettingsBackend() { } /*! @~english @brief List all gsettings keys. @return Return all gsettings keys. */ QStringList GSettingsBackend::keys() const { Q_D(const GSettingsBackend); return d->gsettings->keys(); } /*! @~english @brief Get value of key. @return Return the value of the given \a key. */ QVariant GSettingsBackend::getOption(const QString &key) const { Q_D(const GSettingsBackend); return d->gsettings->get(qtifyName(key)); } /*! @~english @brief Set value to gsettings Use the \a key to save the \a value. */ void GSettingsBackend::doSetOption(const QString &key, const QVariant &value) { Q_D(GSettingsBackend); if (value != d->gsettings->get(qtifyName(key))) { // qDebug() << "doSetOption" << key << d->gsettings->get(qtifyName(key)); d->gsettings->set(qtifyName(key), value); } } /*! @~english @brief Trigger DSettings to sync option to storage. */ void GSettingsBackend::doSync() { Q_EMIT sync(); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/settings/backend/qsettingbackend.cpp000066400000000000000000000043171476226660600231550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "settings/backend/qsettingbackend.h" #include #include #include DCORE_BEGIN_NAMESPACE class QSettingBackendPrivate { public: QSettingBackendPrivate(QSettingBackend *parent) : q_ptr(parent) {} QSettings *settings = nullptr; QMutex writeLock; QSettingBackend *q_ptr; Q_DECLARE_PUBLIC(QSettingBackend) }; /*! @~english @class Dtk::Core::QSettingBackend \inmodule dtkcore @brief Storage DSetttings to an QSettings. */ /*! @~english @brief Save data to filepath with QSettings::NativeFormat format. \a filepath is path to storage data. \a parent */ QSettingBackend::QSettingBackend(const QString &filepath, QObject *parent) : DSettingsBackend(parent), d_ptr(new QSettingBackendPrivate(this)) { Q_D(QSettingBackend); d->settings = new QSettings(filepath, QSettings::NativeFormat, this); qDebug() << "create config" << d->settings->fileName(); } QSettingBackend::~QSettingBackend() { } /*! @~english @brief List all keys of QSettings @return */ QStringList QSettingBackend::keys() const { Q_D(const QSettingBackend); return d->settings->childGroups(); } /*! @~english @brief Get value of key from QSettings \a key @return */ QVariant QSettingBackend::getOption(const QString &key) const { Q_D(const QSettingBackend); d->settings->beginGroup(key); auto value = d->settings->value("value"); d->settings->endGroup(); return value; } /*! @~english @brief Set value of key to QSettings \a key \a value */ void QSettingBackend::doSetOption(const QString &key, const QVariant &value) { Q_D(QSettingBackend); d->writeLock.lock(); d->settings->beginGroup(key); auto oldValue = d->settings->value("value"); if (oldValue != value) { d->settings->setValue("value", value); } d->settings->endGroup(); d->settings->sync(); d->writeLock.unlock(); } /*! @~english @brief Trigger DSettings to save option value to QSettings */ void QSettingBackend::doSync() { Q_D(QSettingBackend); d->settings->sync(); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/settings/dsettings.cpp000066400000000000000000000276071476226660600204330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsettings.h" #include #include #include #include #include #include #include #include "dsettingsoption.h" #include "dsettingsgroup.h" #include "dsettingsbackend.h" DCORE_BEGIN_NAMESPACE class DSettingsPrivate { public: DSettingsPrivate(DSettings *parent) : q_ptr(parent) {} DSettingsBackend *backend = nullptr; QJsonObject meta; QMap options; QMap childGroups; QList childGroupKeys; DSettings *q_ptr; Q_DECLARE_PUBLIC(DSettings) }; /*! @~english @class Dtk::Core::DSettingsBackend \inmodule dtkcore @brief DSettingsBackend is interface of DSettings storage class. Simaple example: @code { "groups": [{ "key": "base", "name": "Basic settings", "groups": [{ "key": "open_action", "name": "Open Action", "options": [{ "key": "alway_open_on_new", "type": "checkbox", "text": "Always Open On New Windows", "default": true }, { "key": "open_file_action", "name": "Open File:", "type": "combobox", "default": "" } ] }, { "key": "new_tab_windows", "name": "New Tab & Window", "options": [{ "key": "new_window_path", "name": "New Window Open:", "type": "combobox", "default": "" }, { "key": "new_tab_path", "name": "New Tab Open:", "type": "combobox", "default": "" } ] } ] }] } @endcode How to read/write key and value: @code // init a storage backend QTemporaryFile tmpFile; tmpFile.open(); auto backend = new Dtk::Core::QSettingBackend(tmpFile.fileName()); // read settings from json auto settings = Dtk::Core::DSettings::fromJsonFile(":/resources/data/dfm-settings.json"); settings->setBackend(backend); // read value auto opt = settings->option("base.new_tab_windows.new_window_path"); qDebug() << opt->value(); // modify value opt->setValue("Test") qDebug() << opt->value(); @endcode @sa Dtk::Core::DSettingsOption @sa Dtk::Core::DSettingsGroup @sa Dtk::Core::DSettingsBackend @sa Dtk::Widget::DSettingsWidgetFactory @sa Dtk::Widget::DSettingsDialog */ /*! @~english @fn virtual QStringList DSettingsBackend::keys() const = 0; @brief return all key of storage. */ /*! @~english @fn virtual QVariant DSettingsBackend::getOption(const QString &key) const = 0; @brief get value by \a key. */ /*! @~english @fn virtual void DSettingsBackend::doSync() = 0; @brief do the real sync action. */ /*! @~english @fn virtual void DSettingsBackend::doSetOption(const QString &key, const QVariant &value) = 0; @brief write \a key / \a value to storage. */ /*! @~english @fn void DSettingsBackend::optionChanged(const QString &key, const QVariant &value); @brief emitted when option \a value changed. */ /*! @~english @fn void DSettingsBackend::sync(); @brief private signal, please do not use it. */ /*! @~english @fn void DSettingsBackend::setOption(const QString &key, const QVariant &value); @brief private signal, please do not use it. \internal \a key \a value */ /*! @~english @class Dtk::Core::DSettings \inmodule dtkcore @brief DSettings is the basic library that provides unified configuration storage and interface generation tools for Dtk applications. DSetting uses json as the description file for the application configuration. The configuration of application query is divided into two basic levels: group / key value. The standard Dtk configuration control generally contains only three levels of group / subgroup / key values. For keys with more than three levels, you can use the. DSettings's API interface reads and writes, but cannot be displayed on standard DSettingsDialogs. Simple configuration file: @code { "groups": [{ "key": "base", "name": "Basic settings", "groups": [{ "key": "open_action", "name": "Open Action", "options": [{ "key": "alway_open_on_new", "type": "checkbox", "text": "Always Open On New Windows", "default": true }, { "key": "open_file_action", "name": "Open File:", "type": "combobox", "default": "" } ] }, { "key": "new_tab_windows", "name": "New Tab & Window", "options": [{ "key": "new_window_path", "name": "New Window Open:", "type": "combobox", "default": "" }, { "key": "new_tab_path", "name": "New Tab Open:", "type": "combobox", "default": "" } ] } ] }] } @endcode The group contains a root group of base with two subgroups: open_action/new_tab_windows, each of which contains several options. The complete access id for the configuration "New Window Open:" is base.new_tab_windows.new_window_path. How to read/write key and value: @code // init a storage backend QTemporaryFile tmpFile; tmpFile.open(); auto backend = new Dtk::Core::QSettingBackend(tmpFile.fileName()); // read settings from json auto settings = Dtk::Core::DSettings::fromJsonFile(":/resources/data/dfm-settings.json"); settings->setBackend(backend); // read value auto opt = settings->option("base.new_tab_windows.new_window_path"); qDebug() << opt->value(); // modify value opt->setValue("Test") qDebug() << opt->value(); @endcode @sa Dtk::Core::DSettingsOption @sa Dtk::Core::DSettingsGroup @sa Dtk::Core::DSettingsBackend @sa Dtk::Widget::DSettingsWidgetFactory @sa Dtk::Widget::DSettingsDialog */ DSettings::DSettings(QObject *parent) : QObject(parent), dd_ptr(new DSettingsPrivate(this)) { } DSettings::~DSettings() { } void DSettings::setBackend(DSettingsBackend *backend) { Q_D(DSettings); if (nullptr == backend) { return; } if (d->backend != nullptr) { qWarning() << "set backend to exist " << d->backend; } d->backend = backend; auto backendWriteThread = new QThread; d->backend->moveToThread(backendWriteThread); connect(d->backend, &DSettingsBackend::optionChanged, this, [ = ](const QString & key, const QVariant & value) { option(key)->setValue(value); }); // exit and delete thread connect(this, &DSettings::destroyed, this, [backendWriteThread](){ if (backendWriteThread->isRunning()) { backendWriteThread->quit(); backendWriteThread->wait(); } backendWriteThread->deleteLater(); }); backendWriteThread->start(); // load form backend loadValue(); } /*! @~english @brief Get DSettings from \a json. The returned data needs to be manually released after use. */ QPointer DSettings::fromJson(const QByteArray &json) { auto settingsPtr = QPointer(new DSettings); settingsPtr->parseJson(json); return settingsPtr; } QPointer DSettings::fromJsonFile(const QString &filepath) { QFile jsonFile(filepath); jsonFile.open(QIODevice::ReadOnly); auto jsonData = jsonFile.readAll(); jsonFile.close(); return DSettings::fromJson(jsonData); } QJsonObject DSettings::meta() const { Q_D(const DSettings); return d->meta; } QStringList DSettings::keys() const { Q_D(const DSettings); return d->options.keys(); } QPointer DSettings::option(const QString &key) const { Q_D(const DSettings); return d->options.value(key); } QVariant DSettings::value(const QString &key) const { Q_D(const DSettings); auto opt = d->options.value(key); if (opt.isNull()) { return QVariant(); } return opt->value(); } QStringList DSettings::groupKeys() const { Q_D(const DSettings); return d->childGroupKeys; } QList > DSettings::groups() const { Q_D(const DSettings); return d->childGroups.values(); } /*! @~english @brief DSettings::group will recurrence find childGroup \a key @return */ QPointer DSettings::group(const QString &key) const { Q_D(const DSettings); auto childKeylist = key.split("."); if (0 >= childKeylist.length()) { return nullptr; } auto mainGroupKey = childKeylist.value(0); if (1 >= childKeylist.length()) { return d->childGroups.value(mainGroupKey); } return d->childGroups.value(mainGroupKey)->childGroup(key); } QList > DSettings::options() const { Q_D(const DSettings); return d->options.values(); } QVariant DSettings::getOption(const QString &key) const { QPointer optionPointer = option(key); if (optionPointer) { return optionPointer->value(); } return QVariant(); } void DSettings::setOption(const QString &key, const QVariant &value) { option(key)->setValue(value); } void DSettings::sync() { Q_D(DSettings); if (!d->backend) { qWarning() << "backend was not setted..!"; return; } d->backend->doSync(); } void DSettings::reset() { Q_D(DSettings); for (auto option : d->options) { if (option->canReset()) { setOption(option->key(), option->defaultValue()); } } if (!d->backend) { qWarning() << "backend was not setted..!"; return; } d->backend->sync(); } void DSettings::parseJson(const QByteArray &json) { Q_D(DSettings); auto jsonDoc = QJsonDocument::fromJson(json); d->meta = jsonDoc.object(); auto mainGroups = d->meta.value("groups"); for (auto groupJson : mainGroups.toArray()) { auto group = DSettingsGroup::fromJson("", groupJson.toObject()); group->setParent(this); for (auto option : group->options()) { d->options.insert(option->key(), option); } d->childGroupKeys << group->key(); d->childGroups.insert(group->key(), group); } for (auto option : d->options.values()) { d->options.insert(option->key(), option); connect(option.data(), &DSettingsOption::valueChanged, this, [ = ](QVariant value) { if (d->backend) { Q_EMIT d->backend->setOption(option->key(), value); } else { qWarning() << "backend was not setted..!"; } Q_EMIT valueChanged(option->key(), value); }); } } void DSettings::loadValue() { Q_D(DSettings); if (!d->backend) { qWarning() << "backend was not setted..!"; return; } for (auto key : d->backend->keys()) { auto value = d->backend->getOption(key); auto opt = option(key); if (!value.isValid() || opt.isNull()) { continue; } opt->blockSignals(true); opt->setValue(value); opt->blockSignals(false); } } DCORE_END_NAMESPACE dtkcore-5.7.12/src/settings/dsettingsgroup.cpp000066400000000000000000000136131476226660600215000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsettingsgroup.h" #include #include #include DCORE_BEGIN_NAMESPACE class DSettingsGroupPrivate { public: DSettingsGroupPrivate(DSettingsGroup *parent) : q_ptr(parent) {} QString key; QString name; bool hide = false; QMap options; QPointer parent; QMap childOptions; QList childOptionKeys; QMap childGroups; QList childGroupKeys; void parseJson(const QString &prefixKey, const QJsonObject &group); DSettingsGroup *q_ptr; Q_DECLARE_PUBLIC(DSettingsGroup) }; /*! @~english @class Dtk::Core::DSettingsGroup \inmodule dtkcore @brief A group of DSettingsOption and DSettingsGroup. DSettingsGroup can contain a lost option and subgroup. */ DSettingsGroup::DSettingsGroup(QObject *parent) : QObject(parent), dd_ptr(new DSettingsGroupPrivate(this)) { } DSettingsGroup::~DSettingsGroup() { } /*! @~english @brief Get direct parent group of this group. @return */ QPointer DSettingsGroup::parentGroup() const { Q_D(const DSettingsGroup); return d->parent; } /*! @~english @brief Change the direct \a parentGroup of this group. */ void DSettingsGroup::setParentGroup(QPointer parentGroup) { Q_D(DSettingsGroup); d->parent = parentGroup; } /*! @~english @brief Return the full key of this group, include all parent. @return eturn the full key of this group, include all parent. */ QString DSettingsGroup::key() const { Q_D(const DSettingsGroup); return d->key; } /*! @~english @brief Get display name of this group, it may be translated. @return Get display name of this group. */ QString DSettingsGroup::name() const { Q_D(const DSettingsGroup); return d->name; } /*! @~english @brief Check this group will show on DSettings dialog. @return true indicates that this option group will be displayed。 */ bool DSettingsGroup::isHidden() const { Q_D(const DSettingsGroup); return d->hide; } /*! @~english @brief Get the child group of groupKey \a groupKey is child group key @return Returns a pointer to a subgroup. */ QPointer DSettingsGroup::childGroup(const QString &groupKey) const { Q_D(const DSettingsGroup); return d->childGroups.value(groupKey); } /*! @~english @brief Get the child option of key \a key is child option key @return Returns a pointer to the child option of key. */ QPointer DSettingsGroup::option(const QString &key) const { Q_D(const DSettingsGroup); return d->childOptions.value(key); } /*! @~english @brief Enum all direct child group of this group @return Returns a list of all subgroup Pointers. */ QList > DSettingsGroup::childGroups() const { Q_D(const DSettingsGroup); QList > grouplist; for (auto groupKey : d->childGroupKeys) { grouplist << d->childGroups.value(groupKey); } return grouplist; } /*! @~english @brief Enum all direct child option with the raw order in json description file. @return Returns a list of all suboption Pointers. */ QList > DSettingsGroup::childOptions() const { Q_D(const DSettingsGroup); QList > optionlist; for (auto optionKey : d->childOptionKeys) { optionlist << d->childOptions.value(optionKey); } return optionlist; } /*! @~english @brief Enum all direct child option of this group. @return Returns a list of all option Pointers. */ QList > DSettingsGroup::options() const { Q_D(const DSettingsGroup); return d->options.values(); } /*! @~english @brief Convert QJsonObject to DSettingsGroup. \a prefixKey instead parse prefix key from parent. \a group is an QJsonObejct instance. @return Returns a group pointer after parsing json. @sa QPointer Dtk::Core::DSettingsOption */ QPointer DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &group) { auto groupPtr = QPointer(new DSettingsGroup); groupPtr->parseJson(prefixKey, group); return groupPtr; } /*! @~english @brief Parse QJsonObject to DSettingsGroup. \a prefixKey instead parse prefix key from parent. \a json is an QJsonObejct instance. @sa QPointer Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json) */ void DSettingsGroup::parseJson(const QString &prefixKey, const QJsonObject &group) { Q_D(DSettingsGroup); d->parseJson(prefixKey, group); } void DSettingsGroupPrivate::parseJson(const QString &prefixKey, const QJsonObject &group) { Q_Q(DSettingsGroup); key = group.value("key").toString(); Q_ASSERT(!key.isEmpty()); key = prefixKey.isEmpty() ? key : prefixKey + "." + key; name = group.value("name").toString(); hide = group.value("hide").toBool(); for (auto optionJson : group.value("options").toArray()) { auto optionObject = optionJson.toObject(); auto option = DSettingsOption::fromJson(key, optionObject); option->setParent(q); options.insert(option->key(), option); childOptions.insert(option->key(), option); childOptionKeys << option->key(); } auto subGroups = group.value("groups").toArray(); for (auto subGroup : subGroups) { auto child = DSettingsGroup::fromJson(key, subGroup.toObject()); child->setParent(q); child->setParentGroup(q); childGroups.insert(child->key(), child); childGroupKeys << child->key(); for (auto option : child->options()) { options.insert(option->key(), option); } } } DCORE_END_NAMESPACE dtkcore-5.7.12/src/settings/dsettingsoption.cpp000066400000000000000000000157361476226660600216640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsettingsoption.h" #include #include #include DCORE_BEGIN_NAMESPACE class DSettingsOptionPrivate { public: DSettingsOptionPrivate(DSettingsOption *parent) : q_ptr(parent) {} void parseJson(const QString &prefixKey, const QJsonObject &option); QPointer parent; QString key; QString name; QString viewType; QVariant defalutValue; QVariant value; QVariantMap datas; bool canReset; bool hidden; DSettingsOption *q_ptr; Q_DECLARE_PUBLIC(DSettingsOption) }; /*! @~english @class Dtk::Core::DSettingsOption \inmodule dtkcore @brief DSettingsOption is the base key/value item of DSettings. */ /*! @~english @fn void DSettingsOption::valueChanged(QVariant value); @brief Emit when option value change. \a value Changed data. */ /*! @~english @fn void DSettingsOption::dataChanged(const QString &dataType, QVariant value); @brief Emit when option data change. \a dataType Changed data type, \a value Changed data. */ /*! @~english @property Dtk::Core::DSettingsOption::value @brief Current value of this option. */ DSettingsOption::DSettingsOption(QObject *parent) : QObject(parent), dd_ptr(new DSettingsOptionPrivate(this)) { } DSettingsOption::~DSettingsOption() { } /*! @~english @brief Get direct parent group of this option. @return Returns the direct parent group of the this option. */ QPointer DSettingsOption::parentGroup() const { Q_D(const DSettingsOption); return d->parent; } /*! @~english @brief Change the direct parent group of this option. \a parentGroup parent group. */ void DSettingsOption::setParentGroup(QPointer parentGroup) { Q_D(DSettingsOption); d->parent = parentGroup; } /*! @~english @brief Return the full key of this option, include all parent. @return Return the full key of this option, include all parent. */ QString DSettingsOption::key() const { Q_D(const DSettingsOption); return d->key; } /*! @~english @brief Get display name of the option, it may be translated. @return Return the name of the option. */ QString DSettingsOption::name() const { Q_D(const DSettingsOption); return d->name; } /*! @~english @brief Check this option can be reset to default value. if false, reset action will not take effect. @return true if can be reset. */ bool DSettingsOption::canReset() const { Q_D(const DSettingsOption); return d->canReset; } /*! @~english @brief Default value of this option, must config in this json desciption file. @return Return the default value of this option. */ QVariant DSettingsOption::defaultValue() const { Q_D(const DSettingsOption); return d->defalutValue; } /*! @~english @brief Get current value of option. @return Return the current value of this option. */ QVariant DSettingsOption::value() const { Q_D(const DSettingsOption); return (!d->value.isValid() || d->value.isNull()) ? d->defalutValue : d->value; } /*! @~english @brief Custom data of option, like QObject::property. \a dataType Data type. @return Data type Indicates the data. @sa QObject::property @sa Dtk::Core::DSettingsOption::setData */ QVariant DSettingsOption::data(const QString &dataType) const { Q_D(const DSettingsOption); return d->datas.value(dataType); } /*! @~english @brief UI widget type of this option. @return Returns the UI widget type of the option. @sa Dtk::Widget::DSettingsWidgetFactory */ QString DSettingsOption::viewType() const { Q_D(const DSettingsOption); return d->viewType; } /*! @~english @brief Check this option will show on DSettings dialog. @return true if option not bind to ui element. */ bool DSettingsOption::isHidden() const { Q_D(const DSettingsOption); return d->hidden; } /*! @~english @brief Convert QJsonObject to DSettingsOption. \a prefixKey instead parse prefix key from parent. \a json is an QJsonObejct instance. @return Return the option data after parsing. */ QPointer DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json) { auto optionPtr = QPointer(new DSettingsOption); optionPtr->parseJson(prefixKey, json); return optionPtr; } /*! @~english @brief Set current value of option. \a value Current value of option. */ void DSettingsOption::setValue(QVariant value) { Q_D(DSettingsOption); // 默认没有设置value时比较默认值。防止reset时出现所有的option都发射valueChanged if (this->value() == value) { return; } d->value = value; Q_EMIT valueChanged(value); } ///*! // * @brief Override default value of json // * \a value // */ //void DSettingsOption::setDefault(QVariant value) //{ // Q_D(DSettingsOption); // d->defalutValue = value; //} /*! @~english @brief Set custom data. \a dataType is data id, just a unique string. \a value of the data id. @sa Dtk::Core::DSettingsOption::data */ void DSettingsOption::setData(const QString &dataType, QVariant value) { Q_D(DSettingsOption); if (d->datas.value(dataType) == value) { return; } d->datas.insert(dataType, value); Q_EMIT dataChanged(dataType, value); } /*! @~english @brief Parse QJsonObject to DSettingsOption. \a prefixKey instead parse prefix key from parent. \a option is an QJsonObejct instance. @sa QPointer Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json) */ void DSettingsOption::parseJson(const QString &prefixKey, const QJsonObject &option) { Q_D(DSettingsOption); d->parseJson(prefixKey, option); } void DSettingsOptionPrivate::parseJson(const QString &prefixKey, const QJsonObject &option) { // Q_Q(Option); key = option.value("key").toString(); Q_ASSERT(!key.isEmpty()); Q_ASSERT(!prefixKey.isEmpty()); key = prefixKey + "." + key; name = option.value("name").toString(); canReset = !option.contains("reset") ? true : option.value("reset").toBool(); defalutValue = option.value("default").toVariant(); hidden = !option.contains("hide") ? false : option.value("hide").toBool(); viewType = option.value("type").toString(); QStringList revserdKeys; revserdKeys << "key" << "name" << "reset" << "default" << "hide" << "type"; auto allKeys = option.keys(); for (auto key : revserdKeys) { allKeys.removeAll(key); } for (auto key : allKeys) { auto value = option.value(key); if (value.isArray()) { QStringList stringlist; for (auto va : value.toArray()) { stringlist << QString("%1").arg(va.toString()); } datas.insert(key, stringlist); } else { datas.insert(key, value.toVariant()); } } } DCORE_END_NAMESPACE dtkcore-5.7.12/src/settings/settings.cmake000066400000000000000000000020321476226660600205460ustar00rootroot00000000000000if(LINUX) file(GLOB SETTINGS_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.cpp ${CMAKE_CURRENT_LIST_DIR}/backend/*.cpp ) file(GLOB SETTINGS_HEADERS ${CMAKE_CURRENT_LIST_DIR}/../../include/settings/*.h ${CMAKE_CURRENT_LIST_DIR}/../../include/settings/backend/*.h ) else() file(GLOB SETTINGS_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.cpp ${CMAKE_CURRENT_LIST_DIR}/backend/dsettingsdconfigbackend.cpp ${CMAKE_CURRENT_LIST_DIR}/backend/qsettingbackend.cpp ) file(GLOB SETTINGS_HEADERS ${CMAKE_CURRENT_LIST_DIR}/../../include/settings/*.h ${CMAKE_CURRENT_LIST_DIR}/../../include/settings/backend/dsettingsdconfigbackend.h ${CMAKE_CURRENT_LIST_DIR}/../../include/settings/backend/qsettingbackend.h ) endif() if(DTK_VERSION_MAJOR) list(REMOVE_ITEM SETTINGS_SOURCES "${CMAKE_CURRENT_LIST_DIR}/backend/gsettingsbackend.cpp") list(REMOVE_ITEM SETTINGS_HEADERS "${CMAKE_CURRENT_LIST_DIR}/../../include/settings/backend/gsettingsbackend.h") endif() set(settings_SRC ${SETTINGS_HEADERS} ${SETTINGS_SOURCES} ) dtkcore-5.7.12/src/util/000077500000000000000000000000001476226660600150245ustar00rootroot00000000000000dtkcore-5.7.12/src/util/README.dpinyin000066400000000000000000000002521476226660600173540ustar00rootroot00000000000000Name: chinese_pinyin Version: 1.0.1 Author: flyerhzm License: MIT License Home: https://github.com/flyerhzm/chinese_pinyin Description: translate chinese hanzi to pinyin dtkcore-5.7.12/src/util/dabstractunitformatter.cpp000066400000000000000000000104341476226660600223250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dabstractunitformatter.h" DCORE_BEGIN_NAMESPACE /*! @~english @class Dtk::Core::DAbstractUnitFormatter @ingroup dutil @brief DAbstractUnitFormatter is a interface which manages the data with the same type DAbstractUnitFormatter provides interfaces including:
1. The maximum value of one unit. 2. The minumum value of one unit. 3. The convert rate to next unit. 4. The string to display one unit. */ /*! @~english @fn int DAbstractUnitFormatter::unitMax() const = 0 @brief Get the maximum unit in the list */ /*! @~english @fn int DAbstractUnitFormatter::unitMin() const = 0 @brief Get the minumum unit in the list */ /*! @~english @fn uint DAbstractUnitFormatter::unitConvertRate(int unitId) const = 0 @brief Get the convert rate to next unit of unitId @param[in] unitId the id of one unit */ /*! @~english @fn qreal DAbstractUnitFormatter::unitValueMax(int unitId) const @brief Get the maximum value of unitId @param[in] unitId the id of one unit */ /*! @~english @fn qreal DAbstractUnitFormatter::unitValueMin(int unitId) const @brief Get the minumum value of unitId @param[in] unitId the id of one unit */ /*! @~english @fn QString DAbstractUnitFormatter::unitStr(int unitId) const = 0 @brief Get the display string of unitId @param[in] unitId the id of one unit */ /*! @~english @brief Constructor of DAbstractUnitFormatter */ DAbstractUnitFormatter::DAbstractUnitFormatter() {} /*! @~english @brief Destructor of DAbstractUnitFormatter */ DAbstractUnitFormatter::~DAbstractUnitFormatter() {} /*! @~english @brief Convert value from unit currentUnit to targetUnit. If currentUnit is smaller than targetUnit, the value will zoom out until the unit is equal to targetUnit. Instead it will zoom in. @param[in] value primitive value @param[in] currentUnit current unit of value @param[in] targetUnit target unit to convert to @return qreal the value with unit targetUnit */ qreal DAbstractUnitFormatter::formatAs(qreal value, int currentUnit, const int targetUnit) const { while (currentUnit < targetUnit) value /= unitConvertRate(currentUnit++); while (currentUnit > targetUnit) value *= unitConvertRate(--currentUnit); return value; } /*! @~english @brief Convert the value to a proper unit. If unit is larger than unitMin() or smaller than unitMax, value will be converted to the unit where value is close to the unitValueMin() @param[in] value primitive value @param[in] unit current unit @return QPair a pair of the converted value and unit */ QPair DAbstractUnitFormatter::format(const qreal value, const int unit) const { // can convert to smaller unit if (unit > unitMin() && value < unitValueMin(unit)) return format(value * unitConvertRate(unit - 1), unit - 1); // can convert to bigger unit if (unit < unitMax() && value > unitValueMax(unit)) return format(value / unitConvertRate(unit), unit + 1); return QPair(value, unit); } /*! @~english @brief A version of format() with all the convert data @param[in] value primitive value @param[in] unit current unit @return QList> pairs of all converted value and unit */ QList> DAbstractUnitFormatter::formatAsUnitList(const qreal value, int unit) const { if (qFuzzyIsNull(value)) return QList>(); if (value < unitValueMin(unit) || unit == unitMin()) { if (unit != unitMin()) return formatAsUnitList(value * unitConvertRate(unit - 1), unit - 1); else return std::move(QList>() << QPair(value, unit)); } ulong _value = ulong(value); QList> ret = formatAsUnitList(value - _value, unit); while (_value && unit != unitMax()) { const ulong rate = unitConvertRate(unit); const ulong r = _value % rate; if (r) ret.push_front(QPair(r, unit)); unit += 1; _value /= rate; } if (_value) ret.push_front(QPair(_value, unit)); return ret; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/ddbusextendedabstractinterface.cpp000066400000000000000000000517451476226660600237730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 Jolla Ltd. // // SPDX-License-Identifier: LGPL-2.1-or-later #include "ddbusextendedpendingcallwatcher_p.h" #include #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusInterface, ("org.freedesktop.DBus")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusPropertiesInterface, ("org.freedesktop.DBus.Properties")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusPropertiesChangedSignal, ("PropertiesChanged")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, propertyChangedSignature, ("propertyChanged(QString,QVariant)")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, propertyInvalidatedSignature, ("propertyInvalidated(QString)")) DDBusExtendedAbstractInterface::DDBusExtendedAbstractInterface( const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent) : QDBusAbstractInterface(service, path, interface, connection, parent) , m_sync(true) , m_useCache(false) , m_getAllPendingCallWatcher(0) , m_propertiesChangedConnected(false) { const_cast(connection) .connect(QString("org.freedesktop.DBus"), QString("/org/freedesktop/DBus"), QString("org.freedesktop.DBus"), QString("NameOwnerChanged"), this, SLOT(onDBusNameOwnerChanged(QString, QString, QString))); } DDBusExtendedAbstractInterface::~DDBusExtendedAbstractInterface() {} void DDBusExtendedAbstractInterface::setSync(bool sync) { setSync(sync, true); } /* * @~english * @note After sync is set to false, it will always return a empty value * if you call the property's get function directly. So you can only get it * through the changed signal when you get an property, and it's also a good * idea to save a cache yourself. */ void DDBusExtendedAbstractInterface::setSync(bool sync, bool autoStart) { m_sync = sync; // init all properties if (autoStart && !m_sync && !isValid()) startServiceProcess(); } void DDBusExtendedAbstractInterface::getAllProperties() { m_lastExtendedError = QDBusError(); if (!isValid()) { QString errorMessage = QStringLiteral("This Extended DBus interface is not valid yet."); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qDebug() << Q_FUNC_INFO << errorMessage; return; } if (!m_sync && m_getAllPendingCallWatcher) { // Call already in place, not repeating ... return; } QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("GetAll")); msg << interface(); if (m_sync) { QDBusMessage reply = connection().call(msg); if (reply.type() != QDBusMessage::ReplyMessage) { m_lastExtendedError = QDBusError(reply); qWarning() << Q_FUNC_INFO << m_lastExtendedError.message(); return; } if (reply.signature() != QLatin1String("a{sv}")) { QString errorMessage = QStringLiteral("Invalid signature \"%1\" in return from call to %2") .arg(reply.signature(), QString(*dBusPropertiesInterface())); qWarning() << Q_FUNC_INFO << errorMessage; m_lastExtendedError = QDBusError(QDBusError::InvalidSignature, errorMessage); return; } QVariantMap value = reply.arguments().at(0).toMap(); onPropertiesChanged(interface(), value, QStringList()); } else { QDBusPendingReply async = connection().asyncCall(msg); m_getAllPendingCallWatcher = new QDBusPendingCallWatcher(async, this); connect(m_getAllPendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *))); return; } } void DDBusExtendedAbstractInterface::connectNotify(const QMetaMethod &signal) { if (signal.methodType() == QMetaMethod::Signal && (signal.methodSignature() == *propertyChangedSignature() || signal.methodSignature() == *propertyInvalidatedSignature())) { if (!m_propertiesChangedConnected) { QStringList argumentMatch; argumentMatch << interface(); connection().connect(service(), path(), *dBusPropertiesInterface(), *dBusPropertiesChangedSignal(), argumentMatch, QString(), this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); m_propertiesChangedConnected = true; return; } } else { QDBusAbstractInterface::connectNotify(signal); } } void DDBusExtendedAbstractInterface::disconnectNotify(const QMetaMethod &signal) { if (signal.methodType() == QMetaMethod::Signal && (signal.methodSignature() == *propertyChangedSignature() || signal.methodSignature() == *propertyInvalidatedSignature())) { if (m_propertiesChangedConnected && 0 == receivers(propertyChangedSignature()->constData()) && 0 == receivers(propertyInvalidatedSignature()->constData())) { QStringList argumentMatch; argumentMatch << interface(); connection().disconnect(service(), path(), *dBusPropertiesInterface(), *dBusPropertiesChangedSignal(), argumentMatch, QString(), this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); m_propertiesChangedConnected = false; return; } } else { QDBusAbstractInterface::disconnectNotify(signal); } } QVariant DDBusExtendedAbstractInterface::internalPropGet(const char *propname, void *propertyPtr) { m_lastExtendedError = QDBusError(); if (m_useCache) { int propertyIndex = metaObject()->indexOfProperty(propname); QMetaProperty metaProperty = metaObject()->property(propertyIndex); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return QVariant{metaProperty.metaType(), propertyPtr}; #else return QVariant(metaProperty.userType(), propertyPtr); #endif } if (m_sync) { QVariant ret = property(propname); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ret.metaType().construct(propertyPtr, ret.constData()); #else QMetaType::construct(ret.userType(), propertyPtr, ret.constData()); #endif return ret; } else { if (!isValid()) { QString errorMessage = QStringLiteral("This Extended DBus interface is not valid yet."); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qDebug() << Q_FUNC_INFO << errorMessage; return QVariant(); } int propertyIndex = metaObject()->indexOfProperty(propname); if (-1 == propertyIndex) { QString errorMessage = QStringLiteral("Got unknown property \"%1\" to read").arg(QString::fromLatin1(propname)); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qWarning() << Q_FUNC_INFO << errorMessage; return QVariant(); } QMetaProperty metaProperty = metaObject()->property(propertyIndex); if (!metaProperty.isReadable()) { QString errorMessage = QStringLiteral("Property \"%1\" is NOT readable").arg(QString::fromLatin1(propname)); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qWarning() << Q_FUNC_INFO << errorMessage; return QVariant(); } // is this metatype registered? const char *expectedSignature = ""; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) if (metaProperty.typeId() != QMetaType::QVariant) { expectedSignature = QDBusMetaType::typeToSignature(metaProperty.metaType()); #else if (int(metaProperty.type()) != QMetaType::QVariant) { expectedSignature = QDBusMetaType::typeToSignature(metaProperty.userType()); #endif if (0 == expectedSignature) { QString errorMessage = QStringLiteral("Type %1 must be registered with Qt D-Bus " "before it can be used to read property " "%2.%3") .arg(metaProperty.typeName(), interface(), propname); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qWarning() << Q_FUNC_INFO << errorMessage; return QVariant(); } } asyncProperty(propname); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return QVariant{metaProperty.metaType(), propertyPtr}; #else return QVariant(metaProperty.userType(), propertyPtr); #endif } } void DDBusExtendedAbstractInterface::internalPropSet(const char *propname, const QVariant &value, void *propertyPtr) { m_lastExtendedError = QDBusError(); if (m_sync) { setProperty(propname, value); } else { if (!isValid()) { QString errorMessage = QStringLiteral("This interface is not yet valid"); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qDebug() << Q_FUNC_INFO << errorMessage; return; } int propertyIndex = metaObject()->indexOfProperty(propname); if (-1 == propertyIndex) { QString errorMessage = QStringLiteral("Got unknown property \"%1\" to write").arg(QString::fromLatin1(propname)); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qWarning() << Q_FUNC_INFO << errorMessage; return; } QMetaProperty metaProperty = metaObject()->property(propertyIndex); if (!metaProperty.isWritable()) { QString errorMessage = QStringLiteral("Property \"%1\" is NOT writable").arg(QString::fromLatin1(propname)); m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); qWarning() << Q_FUNC_INFO << errorMessage; return; } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QVariant variant = QVariant{metaProperty.metaType(), propertyPtr}; #else QVariant variant = QVariant(metaProperty.type(), propertyPtr); #endif variant = value; asyncSetProperty(propname, variant); } } QVariant DDBusExtendedAbstractInterface::asyncProperty(const QString &propertyName) { QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("Get")); msg << interface() << propertyName; QDBusPendingReply async = connection().asyncCall(msg); DDBusExtendedPendingCallWatcher *watcher = new DDBusExtendedPendingCallWatcher(async, propertyName, QVariant(), this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(onAsyncPropertyFinished(QDBusPendingCallWatcher *))); return QVariant(); } void DDBusExtendedAbstractInterface::asyncSetProperty(const QString &propertyName, const QVariant &value) { QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("Set")); msg << interface() << propertyName << QVariant::fromValue(QDBusVariant(value)); QDBusPendingReply<> async = connection().asyncCall(msg); DDBusExtendedPendingCallWatcher *watcher = new DDBusExtendedPendingCallWatcher(async, propertyName, value, this); connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher *)), this, SLOT(onAsyncSetPropertyFinished(QDBusPendingCallWatcher *))); } void DDBusExtendedAbstractInterface::startServiceProcess() { const QString &servName = service(); if (isValid()) { qWarning() << "Service" << servName << "is already started."; return; } QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/", *dBusInterface(), QStringLiteral("StartServiceByName")); msg << servName << quint32(0); QDBusPendingReply async = connection().asyncCall(msg); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &DDBusExtendedAbstractInterface::onStartServiceProcessFinished); } void DDBusExtendedAbstractInterface::onStartServiceProcessFinished(QDBusPendingCallWatcher *w) { if (w->isError()) { m_lastExtendedError = w->error(); } else { m_lastExtendedError = QDBusError(); } QDBusPendingReply reply = *w; Q_EMIT serviceStartFinished(reply.value()); w->deleteLater(); } void DDBusExtendedAbstractInterface::onAsyncPropertyFinished(QDBusPendingCallWatcher *w) { DDBusExtendedPendingCallWatcher *watcher = qobject_cast(w); Q_ASSERT(watcher); QDBusPendingReply reply = *watcher; if (reply.isError()) { m_lastExtendedError = reply.error(); } else { int propertyIndex = metaObject()->indexOfProperty(watcher->asyncProperty().toLatin1().constData()); QVariant value = demarshall(interface(), metaObject()->property(propertyIndex), reply.value(), &m_lastExtendedError); if (m_lastExtendedError.isValid()) { Q_EMIT propertyInvalidated(watcher->asyncProperty()); } else { Q_EMIT propertyChanged(watcher->asyncProperty(), value); } } Q_EMIT asyncPropertyFinished(watcher->asyncProperty()); watcher->deleteLater(); } void DDBusExtendedAbstractInterface::onAsyncSetPropertyFinished(QDBusPendingCallWatcher *w) { DDBusExtendedPendingCallWatcher *watcher = qobject_cast(w); Q_ASSERT(watcher); QDBusPendingReply<> reply = *watcher; if (reply.isError()) { m_lastExtendedError = reply.error(); } else { m_lastExtendedError = QDBusError(); } Q_EMIT asyncSetPropertyFinished(watcher->asyncProperty()); // Resetting the property to its previous value after sending the // finished signal if (!reply.isError()) { m_lastExtendedError = QDBusError(); Q_EMIT propertyChanged(watcher->asyncProperty(), watcher->previousValue()); } watcher->deleteLater(); } void DDBusExtendedAbstractInterface::onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *watcher) { m_getAllPendingCallWatcher = 0; QDBusPendingReply reply = *watcher; if (reply.isError()) { m_lastExtendedError = reply.error(); } else { m_lastExtendedError = QDBusError(); } Q_EMIT asyncGetAllPropertiesFinished(); if (!reply.isError()) { onPropertiesChanged(interface(), reply.value(), QStringList()); } watcher->deleteLater(); } void DDBusExtendedAbstractInterface::onPropertiesChanged(const QString &interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) { if (interfaceName == interface()) { QVariantMap::const_iterator i = changedProperties.constBegin(); while (i != changedProperties.constEnd()) { int propertyIndex = metaObject()->indexOfProperty(i.key().toLatin1().constData()); if (-1 == propertyIndex) { qDebug() << Q_FUNC_INFO << "Got unknown changed property" << i.key(); } else { QVariant value = demarshall(interface(), metaObject()->property(propertyIndex), i.value(), &m_lastExtendedError); if (m_lastExtendedError.isValid()) { Q_EMIT propertyInvalidated(i.key()); } else { Q_EMIT propertyChanged(i.key(), value); } } ++i; } QStringList::const_iterator j = invalidatedProperties.constBegin(); while (j != invalidatedProperties.constEnd()) { if (-1 == metaObject()->indexOfProperty(j->toLatin1().constData())) { qDebug() << Q_FUNC_INFO << "Got unknown invalidated property" << *j; } else { m_lastExtendedError = QDBusError(); Q_EMIT propertyInvalidated(*j); } ++j; } } } void DDBusExtendedAbstractInterface::onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) { if (name == service() && oldOwner.isEmpty()) { m_dbusOwner = newOwner; Q_EMIT serviceValidChanged(true); } else if (name == m_dbusOwner && newOwner.isEmpty()) { m_dbusOwner.clear(); Q_EMIT serviceValidChanged(false); } } QVariant DDBusExtendedAbstractInterface::demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error) { Q_ASSERT(metaProperty.isValid()); Q_ASSERT(error != 0); if (value.userType() == metaProperty.userType()) { // No need demarshalling. Passing back straight away ... *error = QDBusError(); return value; } QString errorMessage; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QVariant result = QVariant{metaProperty.metaType()}; const char *expectedSignature = QDBusMetaType::typeToSignature(metaProperty.metaType()); #else QVariant result = QVariant(metaProperty.userType(), (void *)0); const char *expectedSignature = QDBusMetaType::typeToSignature(metaProperty.userType()); #endif if (value.userType() == qMetaTypeId()) { // demarshalling a DBus argument ... QDBusArgument dbusArg = value.value(); if (expectedSignature == dbusArg.currentSignature().toLatin1()) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QDBusMetaType::demarshall(dbusArg, metaProperty.metaType(), result.data()); #else QDBusMetaType::demarshall(dbusArg, metaProperty.userType(), result.data()); #endif if (!result.isValid()) { errorMessage = QStringLiteral("Unexpected failure demarshalling " "upon PropertiesChanged signal arrival " "for property `%3.%4' (expected type `%5' (%6))") .arg(interface, QString::fromLatin1(metaProperty.name()), QString::fromLatin1(metaProperty.typeName()), expectedSignature); } } else { errorMessage = QStringLiteral("Unexpected `user type' (%2) " "upon PropertiesChanged signal arrival " "for property `%3.%4' (expected type `%5' (%6))") .arg(dbusArg.currentSignature(), interface, QString::fromLatin1(metaProperty.name()), QString::fromLatin1(metaProperty.typeName()), QString::fromLatin1(expectedSignature)); } } else { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) const char *actualSignature = QDBusMetaType::typeToSignature(value.metaType()); #else const char *actualSignature = QDBusMetaType::typeToSignature(value.userType()); #endif errorMessage = QStringLiteral("Unexpected `%1' (%2) " "upon PropertiesChanged signal arrival " "for property `%3.%4' (expected type `%5' (%6))") .arg(QString::fromLatin1(value.typeName()), QString::fromLatin1(actualSignature), interface, QString::fromLatin1(metaProperty.name()), QString::fromLatin1(metaProperty.typeName()), QString::fromLatin1(expectedSignature)); } if (errorMessage.isEmpty()) { *error = QDBusError(); } else { *error = QDBusMessage::createError(QDBusError::InvalidSignature, errorMessage); qDebug() << Q_FUNC_INFO << errorMessage; } return result; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/ddbusextendedpendingcallwatcher.cpp000066400000000000000000000013511476226660600241310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 Jolla Ltd. // // SPDX-License-Identifier: LGPL-2.1-or-later #include "ddbusextendedpendingcallwatcher_p.h" DCORE_BEGIN_NAMESPACE DDBusExtendedPendingCallWatcher::DDBusExtendedPendingCallWatcher(const QDBusPendingCall &call, const QString &asyncProperty, const QVariant &previousValue, QObject *parent) : QDBusPendingCallWatcher(call, parent) , m_asyncProperty(asyncProperty) , m_previousValue(previousValue) { } DDBusExtendedPendingCallWatcher::~DDBusExtendedPendingCallWatcher() {} DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/ddbusextendedpendingcallwatcher_p.h000066400000000000000000000024511476226660600241170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2015 Jolla Ltd. // // SPDX-License-Identifier: LGPL-2.1-or-later // // W A R N I N G // ------------- // // This file is not part of the public API. This header file may // change from version to version without notice, or even be // removed. // // We mean it. // // #ifndef DDBUSEXTENDEDPENDINGCALLWATCHER_P_H #define DDBUSEXTENDEDPENDINGCALLWATCHER_P_H #include "dtkcore_global.h" #include #include DCORE_BEGIN_NAMESPACE class DDBusExtendedPendingCallWatcher : public QDBusPendingCallWatcher { Q_OBJECT public: explicit DDBusExtendedPendingCallWatcher(const QDBusPendingCall &call, const QString &asyncProperty, const QVariant &previousValue, QObject *parent = 0); ~DDBusExtendedPendingCallWatcher(); Q_PROPERTY(QString AsyncProperty READ asyncProperty) inline QString asyncProperty() const { return m_asyncProperty; } Q_PROPERTY(QVariant PreviousValue READ previousValue) inline QVariant previousValue() const { return m_previousValue; } private: QString m_asyncProperty; QVariant m_previousValue; }; DCORE_END_NAMESPACE #endif /* DDBUSEXTENDEDPENDINGCALLWATCHER_P_H */ dtkcore-5.7.12/src/util/ddbusinterface.cpp000066400000000000000000000262211476226660600205150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddbusinterface.h" #include "ddbusinterface_p.h" #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE static const QString &FreedesktopService = QStringLiteral("org.freedesktop.DBus"); static const QString &FreedesktopPath = QStringLiteral("/org/freedesktop/DBus"); static const QString &FreedesktopInterface = QStringLiteral("org.freedesktop.DBus"); static const QString &NameOwnerChanged = QStringLiteral("NameOwnerChanged"); static const QString &PropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties"); static const QString &PropertiesChanged = QStringLiteral("PropertiesChanged"); static const char *PropertyName = "propname"; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #define PropType(metaProperty) metaProperty.metaType() #else #define PropType(metaProperty) metaProperty.userType() #endif static QVariant demarshall(const QMetaProperty &metaProperty, const QVariant &value) { // if the value is the same with parent one, return value if (value.userType() == metaProperty.userType()) return value; // unwrap the value with parent one QVariant result = QVariant(PropType(metaProperty), nullptr); if (value.userType() == qMetaTypeId()) { QDBusArgument dbusArg = value.value(); QDBusMetaType::demarshall(dbusArg, PropType(metaProperty), result.data()); } return result; } DDBusInterfacePrivate::DDBusInterfacePrivate(DDBusInterface *interface, QObject *parent) : QObject(interface) , m_parent(parent) , m_serviceValid(false) , q_ptr(interface) { QDBusMessage message = QDBusMessage::createMethodCall(FreedesktopService, FreedesktopPath, FreedesktopInterface, "NameHasOwner"); message << interface->service(); interface->connection().callWithCallback(message, this, SLOT(onDBusNameHasOwner(bool))); interface->connection().connect(interface->service(), interface->path(), PropertiesInterface, PropertiesChanged, {interface->interface()}, QString(), this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); } void DDBusInterfacePrivate::updateProp(const char *propName, const QVariant &value) { if (!m_parent) return; const QMetaObject *metaObj = m_parent->metaObject(); const char *typeName(value.typeName()); void *data = const_cast(value.data()); int propertyIndex = metaObj->indexOfProperty(propName); QVariant result = value; // TODO: it now cannot convert right, Like QMap // if there is property, then try to convert with property if (propertyIndex != -1) { QMetaProperty metaProperty = metaObj->property(propertyIndex); result = demarshall(metaProperty, value); data = const_cast(result.data()); typeName = result.typeName(); } else if (value.canConvert()) { auto dbusType = qvariant_cast(value); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto dbusMetaType = QDBusMetaType::signatureToMetaType(dbusType.currentSignature().toUtf8()); typeName = dbusMetaType.name(); void *dbusData = dbusMetaType.create(); QDBusMetaType::demarshall(dbusType, dbusMetaType, dbusData); data = dbusData; QObject dbusDataDeleter; QObject::connect(&dbusDataDeleter, &QObject::destroyed, m_parent, [dbusData, dbusMetaType]() { dbusMetaType.destroy(dbusData); }, Qt::QueuedConnection); #else auto dbusMetaType = QDBusMetaType::signatureToType(dbusType.currentSignature().toUtf8()); typeName = QMetaType::typeName(dbusMetaType); void *dbusData = QMetaType::create(dbusMetaType); QDBusMetaType::demarshall(dbusType, dbusMetaType, dbusData); data = dbusData; // release dbus data of `QMetaType::create`. QObject dbusDataDeleter; QObject::connect(&dbusDataDeleter, &QObject::destroyed, m_parent, [dbusData, dbusMetaType]() { QMetaType::destroy(dbusMetaType, dbusData); }, Qt::QueuedConnection); #endif } QByteArray baSignal = QStringLiteral("%1Changed(%2)").arg(propName).arg(typeName).toLatin1(); int i = metaObj->indexOfSignal(baSignal.data()); if (i != -1) { auto method = metaObj->method(i); if (method.parameterCount() == 1) { method.invoke(m_parent, Qt::DirectConnection, QGenericArgument(method.parameterTypes().first(), data)); } else { method.invoke(m_parent, Qt::DirectConnection); } } else { qDebug() << "It's not exist the property:[" << propName << "] for parent:" << m_parent << ", interface:" << q_ptr->interface() << ", and It's changed value is:" << value; } } void DDBusInterfacePrivate::initDBusConnection() { if (!m_parent) return; Q_Q(DDBusInterface); QDBusConnection connection = q->connection(); QStringList signalList; QDBusInterface inter(q->service(), q->path(), q->interface(), connection); const QMetaObject *meta = inter.metaObject(); for (int i = meta->methodOffset(); i < meta->methodCount(); ++i) { const QMetaMethod &method = meta->method(i); if (method.methodType() == QMetaMethod::Signal) { signalList << method.methodSignature(); } } const QMetaObject *parentMeta = m_parent->metaObject(); for (const QString &signal : signalList) { int i = parentMeta->indexOfSignal(QMetaObject::normalizedSignature(signal.toLatin1())); if (i != -1) { const QMetaMethod &parentMethod = parentMeta->method(i); connection.connect(q->service(), q->path(), q->interface(), parentMethod.name(), m_parent, QT_STRINGIFY(QSIGNAL_CODE) + parentMethod.methodSignature()); } } } void DDBusInterfacePrivate::onPropertiesChanged(const QString &interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties) { Q_UNUSED(interfaceName) Q_UNUSED(invalidatedProperties) for (QVariantMap::const_iterator it = changedProperties.cbegin(); it != changedProperties.cend(); ++it) updateProp((it.key() + m_suffix).toLatin1(), it.value()); } void DDBusInterfacePrivate::onAsyncPropertyFinished(QDBusPendingCallWatcher *w) { QDBusPendingReply reply = *w; if (!reply.isError()) { updateProp(w->property(PropertyName).toString().toLatin1(), reply.value()); } w->deleteLater(); } void DDBusInterfacePrivate::setServiceValid(bool valid) { if (m_serviceValid != valid) { Q_Q(DDBusInterface); m_serviceValid = valid; Q_EMIT q->serviceValidChanged(m_serviceValid); } } void DDBusInterfacePrivate::onDBusNameHasOwner(bool valid) { Q_Q(DDBusInterface); setServiceValid(valid); if (valid) initDBusConnection(); else q->connection().connect(FreedesktopService, FreedesktopPath, FreedesktopInterface, NameOwnerChanged, this, SLOT(onDBusNameOwnerChanged(QString, QString, QString))); } void DDBusInterfacePrivate::onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) { Q_Q(DDBusInterface); if (name == q->service() && oldOwner.isEmpty()) { initDBusConnection(); q->connection().disconnect(FreedesktopService, FreedesktopPath, FreedesktopInterface, NameOwnerChanged, this, SLOT(onDBusNameOwnerChanged(QString, QString, QString))); setServiceValid(true); } else if (name == q->service() && newOwner.isEmpty()) setServiceValid(false); } ////////////////////////////////////////////////////////// // class DDBusInterface ////////////////////////////////////////////////////////// DDBusInterface::DDBusInterface(const QString &service, const QString &path, const QString &interface, const QDBusConnection &connection, QObject *parent) : QDBusAbstractInterface(service, path, interface.toLatin1(), connection, parent) , d_ptr(new DDBusInterfacePrivate(this, parent)) { } DDBusInterface::~DDBusInterface() {} bool DDBusInterface::serviceValid() const { Q_D(const DDBusInterface); return d->m_serviceValid; } QString DDBusInterface::suffix() const { Q_D(const DDBusInterface); return d->m_suffix; } void DDBusInterface::setSuffix(const QString &suffix) { Q_D(DDBusInterface); d->m_suffix = suffix; } inline QString originalPropname(const char *propname, QString suffix) { QString propStr(propname); return propStr.left(propStr.length() - suffix.length()); } QVariant DDBusInterface::property(const char *propName) { Q_D(DDBusInterface); QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), PropertiesInterface, QStringLiteral("Get")); msg << interface() << originalPropname(propName, d->m_suffix); QDBusPendingReply prop = connection().asyncCall(msg); if (prop.value().isValid()) { // if there is no parent, return value if (!parent()) { qWarning() << "you use it without parent, and if the value is not valid, you may get nothing"; return prop.value(); } auto metaObject = parent()->metaObject(); QVariant propresult = prop.value(); int i = metaObject->indexOfProperty(propName); if (i != -1) { QMetaProperty metaProperty = metaObject->property(i); // try to use property in parent to unwrap the value propresult = demarshall(metaProperty, propresult); } return propresult; } QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(prop, this); watcher->setProperty(PropertyName, propName); connect(watcher, &QDBusPendingCallWatcher::finished, d, &DDBusInterfacePrivate::onAsyncPropertyFinished); return QVariant(); } void DDBusInterface::setProperty(const char *propName, const QVariant &value) { Q_D(const DDBusInterface); QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), PropertiesInterface, QStringLiteral("Set")); msg << interface() << originalPropname(propName, d->m_suffix) << QVariant::fromValue(QDBusVariant(value)); QDBusPendingReply reply = connection().asyncCall(msg); reply.waitForFinished(); if (!reply.isValid()) { qWarning() << reply.error().message(); } } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/ddbusinterface_p.h000066400000000000000000000021041476226660600204730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include "ddbusinterface.h" class QDBusPendingCallWatcher; DCORE_BEGIN_NAMESPACE class DDBusInterfacePrivate : public QObject { Q_OBJECT public: explicit DDBusInterfacePrivate(DDBusInterface *interface, QObject *parent); void updateProp(const char *propName, const QVariant &value); void initDBusConnection(); void setServiceValid(bool valid); private Q_SLOTS: void onPropertiesChanged(const QString &interfaceName, const QVariantMap &changedProperties, const QStringList &invalidatedProperties); void onAsyncPropertyFinished(QDBusPendingCallWatcher *w); void onDBusNameHasOwner(bool valid); void onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); public: QObject *m_parent; QString m_suffix; bool m_serviceValid; DDBusInterface *q_ptr; Q_DECLARE_PUBLIC(DDBusInterface) }; DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/ddbussender.cpp000066400000000000000000000054641476226660600200430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddbussender.h" #include #include DDBusSender::DDBusSender() : m_dbusData(std::make_shared()) { } DDBusSender DDBusSender::service(const QString &service) { m_dbusData->service = service; return *this; } DDBusSender DDBusSender::interface(const QString &interface) { m_dbusData->interface = interface; return *this; } DDBusCaller DDBusSender::method(const QString &method) { return DDBusCaller(method, m_dbusData); } DDBusProperty DDBusSender::property(const QString &property) { return DDBusProperty(property, m_dbusData); } DDBusSender DDBusSender::system() { DDBusSender self; self.type(QDBusConnection::SystemBus); return self; } DDBusSender DDBusSender::path(const QString &path) { m_dbusData->path = path; return *this; } DDBusSender DDBusSender::type(const QDBusConnection::BusType busType) { switch (busType) { case QDBusConnection::SessionBus: m_dbusData->connection = QDBusConnection::sessionBus(); break; case QDBusConnection::SystemBus: m_dbusData->connection = QDBusConnection::systemBus(); break; default: Q_UNREACHABLE_IMPL(); } return *this; } DDBusData::DDBusData() : connection(QDBusConnection::sessionBus()) { } QDBusPendingCall DDBusData::asyncCallWithArguments(const QString &method, const QVariantList &arguments, const QString &iface) { // When creating a QDBusAbstractInterface, Qt will try to invoke introspection into this dbus path; // This is costing in some cases when introspection is not ready; // Cause this is an asynchronous method, it'd be better not to wait for anything, just leave this to caller; // Use QDBusMessage to invoke directly instead of creating a QDBusInterface. const QString calledInterface = iface.isEmpty() ? interface : iface; QDBusMessage methodCall = QDBusMessage::createMethodCall(service, path, calledInterface, method); methodCall.setArguments(arguments); return connection.asyncCall(methodCall); } QDBusPendingCall DDBusCaller::call() { return m_dbusData->asyncCallWithArguments(m_methodName, m_arguments); } DDBusCaller::DDBusCaller(const QString &method, std::shared_ptr data) : m_dbusData(data) , m_methodName(method) { } QDBusPendingCall DDBusProperty::get() { QVariantList args{QVariant::fromValue(m_dbusData->interface), QVariant::fromValue(m_propertyName)}; return m_dbusData->asyncCallWithArguments(QStringLiteral("Get"), args, QStringLiteral("org.freedesktop.DBus.Properties")); } DDBusProperty::DDBusProperty(const QString &property, std::shared_ptr data) : m_dbusData(data) , m_propertyName(property) { } dtkcore-5.7.12/src/util/ddisksizeformatter.cpp000066400000000000000000000014311476226660600214440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddisksizeformatter.h" #include DCORE_BEGIN_NAMESPACE DDiskSizeFormatter::DDiskSizeFormatter() : DAbstractUnitFormatter() { } QString DDiskSizeFormatter::unitStr(int unitId) const { switch (unitId) { case B: return QStringLiteral("B"); case K: return QStringLiteral("KB"); case M: return QStringLiteral("MB"); case G: return QStringLiteral("GB"); case T: return QStringLiteral("TB"); } return QString(); } DDiskSizeFormatter DDiskSizeFormatter::rate(int rate) { m_rate = rate; return *this; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dexportedinterface.cpp000066400000000000000000000071171476226660600214150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dexportedinterface.h" #include "base/private/dobject_p.h" #include #include #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE namespace DUtil { class DExportedInterfacePrivate; class DExportedInterfaceDBusInterface : public QObject, protected QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "com.deepin.ExportedInterface") public: DExportedInterfaceDBusInterface(DExportedInterfacePrivate *priv); public Q_SLOTS: QStringList list(); QString help(const QString &action); QDBusVariant invoke(QString action, QString parameters); private: DExportedInterfacePrivate *p; }; class DExportedInterfacePrivate : public DObjectPrivate { public: DExportedInterfacePrivate(DExportedInterface *q); private: QStringList actionHelp(QString action, int indent); QHash, QString>> actions; QScopedPointer dbusif; D_DECLARE_PUBLIC(DExportedInterface) friend class DExportedInterfaceDBusInterface; }; DExportedInterface::DExportedInterface(QObject *parent) : QObject(parent), DObject(*new DExportedInterfacePrivate(this)) { D_D(DExportedInterface); QDBusConnection::sessionBus().registerObject("/", d->dbusif.data(), QDBusConnection::RegisterOption::ExportAllSlots); } DExportedInterface::~DExportedInterface() { QDBusConnection::sessionBus().unregisterObject("/"); } void DExportedInterface::registerAction(const QString &action, const QString &description, const std::function handler) { D_D(DExportedInterface); d->actions[action] = {handler, description}; } QVariant DExportedInterface::invoke(const QString &action, const QString ¶meters) const { D_DC(DExportedInterface); if (auto func = d->actions.value(action).first) { return func(parameters); } return QVariant(); } DExportedInterfacePrivate::DExportedInterfacePrivate(DExportedInterface *q) : DObjectPrivate(q) , dbusif(new DExportedInterfaceDBusInterface(this)) {} QStringList DExportedInterfacePrivate::actionHelp(QString action, int indent) { QStringList ret; if (actions.contains(action)) { ret << QString(indent * 2, ' ') + QString("%1: %2").arg(action).arg(actions[action].second); } return ret; } DExportedInterfaceDBusInterface::DExportedInterfaceDBusInterface(DExportedInterfacePrivate *priv) : QObject(nullptr) , p(priv) {} QStringList DExportedInterfaceDBusInterface::list() { return p->actions.keys(); } QString DExportedInterfaceDBusInterface::help(const QString &action) { if (action.length()) { return p->actionHelp(action, 0).join('\n'); } else { QString ret = "Available actions:"; QStringList actions = p->actions.keys(); actions.sort(); for (auto action : actions) { ret += QString("\n\n") + p->actionHelp(action, 1).join('\n'); } return ret; } } QDBusVariant DExportedInterfaceDBusInterface::invoke(QString action, QString parameters) { QDBusVariant ret; if (!p->actions.contains(action)) { sendErrorReply(QDBusError::ErrorType::InvalidArgs, QString("Action \"%1\" is not registered").arg(action)); } else { ret.setVariant(p->q_func()->invoke(action, parameters)); } return ret; } } DCORE_END_NAMESPACE #include "dexportedinterface.moc" dtkcore-5.7.12/src/util/dfileservices_dummy.cpp000066400000000000000000000056421476226660600216010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfileservices.h" DCORE_BEGIN_NAMESPACE static QStringList urls2uris(const QList &urls) { QStringList list; list.reserve(urls.size()); for (const QUrl url : urls) { list << url.toString(); } return list; } static QList path2urls(const QList &paths) { QList list; list.reserve(paths.size()); for (const QString &path : paths) { list << QUrl::fromLocalFile(path); } return list; } bool DFileServices::showFolder(QString localFilePath, const QString &startupId) { Q_UNUSED(localFilePath); Q_UNUSED(startupId); return false; } bool DFileServices::showFolders(const QList localFilePaths, const QString &startupId) { Q_UNUSED(localFilePaths); Q_UNUSED(startupId); return false; } bool DFileServices::showFolder(QUrl url, const QString &startupId) { Q_UNUSED(url); Q_UNUSED(startupId); return false; } bool DFileServices::showFolders(const QList urls, const QString &startupId) { Q_UNUSED(urls); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItemPropertie(QString localFilePath, const QString &startupId) { Q_UNUSED(localFilePath); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItemProperties(const QList localFilePaths, const QString &startupId) { Q_UNUSED(localFilePaths); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItemPropertie(QUrl url, const QString &startupId) { Q_UNUSED(url); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItemProperties(const QList urls, const QString &startupId) { Q_UNUSED(urls); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItem(QString localFilePath, const QString &startupId) { Q_UNUSED(localFilePath); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItems(const QList localFilePaths, const QString &startupId) { Q_UNUSED(localFilePaths); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItem(QUrl url, const QString &startupId) { Q_UNUSED(url); Q_UNUSED(startupId); return false; } bool DFileServices::showFileItems(const QList urls, const QString &startupId) { Q_UNUSED(urls); Q_UNUSED(startupId); return false; } bool DFileServices::trash(QString localFilePath) { Q_UNUSED(localFilePath); return false; } bool DFileServices::trash(const QList localFilePaths) { Q_UNUSED(localFilePaths); return false; } bool DFileServices::trash(QUrl url) { Q_UNUSED(url); return false; } bool DFileServices::trash(const QList urls) { Q_UNUSED(urls); return false; } QString DFileServices::errorMessage() { return QString(); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dfileservices_linux.cpp000066400000000000000000000071371476226660600216060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include "dfileservices.h" DCORE_BEGIN_NAMESPACE #define EASY_CALL_DBUS(name)\ QDBusInterface *interface = fileManager1DBusInterface();\ return interface && interface->call(#name, urls2uris(urls), startupId).type() != QDBusMessage::ErrorMessage; static QDBusInterface *fileManager1DBusInterface() { static QDBusInterface interface(QStringLiteral("org.freedesktop.FileManager1"), QStringLiteral("/org/freedesktop/FileManager1"), QStringLiteral("org.freedesktop.FileManager1")); return &interface; } static QStringList urls2uris(const QList &urls) { QStringList list; list.reserve(urls.size()); for (const QUrl &url : urls) { list << url.toString(); } return list; } static QList path2urls(const QList &paths) { QList list; list.reserve(paths.size()); for (const QString &path : paths) { list << QUrl::fromLocalFile(path); } return list; } bool DFileServices::showFolder(QString localFilePath, const QString &startupId) { return showFolder(QUrl::fromLocalFile(localFilePath), startupId); } bool DFileServices::showFolders(const QList localFilePaths, const QString &startupId) { return showFolders(path2urls(localFilePaths), startupId); } bool DFileServices::showFolder(QUrl url, const QString &startupId) { return showFolders(QList() << url, startupId); } bool DFileServices::showFolders(const QList urls, const QString &startupId) { EASY_CALL_DBUS(ShowFolders) } bool DFileServices::showFileItemPropertie(QString localFilePath, const QString &startupId) { return showFileItemPropertie(QUrl::fromLocalFile(localFilePath), startupId); } bool DFileServices::showFileItemProperties(const QList localFilePaths, const QString &startupId) { return showFileItemProperties(path2urls(localFilePaths), startupId); } bool DFileServices::showFileItemPropertie(QUrl url, const QString &startupId) { return showFileItemProperties(QList() << url, startupId); } bool DFileServices::showFileItemProperties(const QList urls, const QString &startupId) { EASY_CALL_DBUS(ShowItemProperties) } bool DFileServices::showFileItem(QString localFilePath, const QString &startupId) { return showFileItem(QUrl::fromLocalFile(localFilePath), startupId); } bool DFileServices::showFileItems(const QList localFilePaths, const QString &startupId) { return showFileItems(path2urls(localFilePaths), startupId); } bool DFileServices::showFileItem(QUrl url, const QString &startupId) { return showFileItems(QList() << url, startupId); } bool DFileServices::showFileItems(const QList urls, const QString &startupId) { EASY_CALL_DBUS(ShowItems) } bool DFileServices::trash(QString localFilePath) { return trash(QUrl::fromLocalFile(localFilePath)); } bool DFileServices::trash(const QList localFilePaths) { return trash(path2urls(localFilePaths)); } bool DFileServices::trash(QUrl url) { return trash(QList() << url); } bool DFileServices::trash(const QList urls) { QDBusInterface *interface = fileManager1DBusInterface(); return interface && interface->call("Trash", urls2uris(urls)).type() != QDBusMessage::ErrorMessage; } QString DFileServices::errorMessage() { return fileManager1DBusInterface()->lastError().message(); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dnotifysender.cpp000066400000000000000000000040041476226660600204030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dnotifysender.h" #include "ddbussender.h" DCORE_BEGIN_NAMESPACE namespace DUtil { struct DNotifyData { uint m_replaceId; int m_timeOut; QString m_body; QString m_summary; QString m_appIcon; QString m_appName; QStringList m_actions; QVariantMap m_hints; }; DNotifySender::DNotifySender(const QString &summary) : m_dbusData(std::make_shared()) { m_dbusData->m_summary = summary; } DNotifySender DNotifySender::appName(const QString &appName) { m_dbusData->m_appName = appName; return *this; } DNotifySender DNotifySender::appIcon(const QString &appIcon) { m_dbusData->m_appIcon = appIcon; return *this; } DNotifySender DNotifySender::appBody(const QString &appBody) { m_dbusData->m_body = appBody; return *this; } DNotifySender DNotifySender::replaceId(const uint replaceId) { m_dbusData->m_replaceId = replaceId; return *this; } DNotifySender DNotifySender::timeOut(const int timeOut) { m_dbusData->m_timeOut = timeOut; return *this; } DNotifySender DNotifySender::actions(const QStringList &actions) { m_dbusData->m_actions = actions; return *this; } DNotifySender DNotifySender::hints(const QVariantMap &hints) { m_dbusData->m_hints = hints; return *this; } QDBusPendingCall DNotifySender::call() { return DDBusSender() .service("org.freedesktop.Notifications") .path("/org/freedesktop/Notifications") .interface("org.freedesktop.Notifications") .method(QString("Notify")) .arg(m_dbusData->m_appName) .arg(m_dbusData->m_replaceId) .arg(m_dbusData->m_appIcon) .arg(m_dbusData->m_summary) .arg(m_dbusData->m_body) .arg(m_dbusData->m_actions) .arg(m_dbusData->m_hints) .arg(m_dbusData->m_timeOut) .call(); } } // namespace DUtil DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dpinyin.cpp000066400000000000000000000125231476226660600172050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dpinyin.h" #include #include #include #include #include DCORE_BEGIN_NAMESPACE static QHash dict = {}; const char kDictFile[] = ":/dpinyin/resources/dpinyin.dict"; static void InitDict() { if (!dict.isEmpty()) { return; } dict.reserve(25333); QFile file(kDictFile); if (!file.open(QIODevice::ReadOnly)) return; QByteArray content = file.readAll(); file.close(); QTextStream stream(&content, QIODevice::ReadOnly); while (!stream.atEnd()) { const QString line = stream.readLine(); // comment if (line.startsWith("#")) continue; const QStringList items = line.left(line.indexOf("#")).split(QChar(':')); if (items.size() == 2) { dict.insert(items[0].toUInt(nullptr, 16), items[1].trimmed()); } } } static void initToneTable(QMap &toneTable) { if (toneTable.size() > 0) return; const QString ts = "aāáǎà,oōóǒò,eēéěè,iīíǐì,uūúǔù,vǖǘǚǜ"; for (const QString &s : ts.split(",")) { for (int i = 1; i < s.length(); ++i) { toneTable.insert(s.at(i), QString("%1%2").arg(s.at(0)).arg(i)); } } } static QString toned(const QString &str, ToneStyle ts) { // TS_Tone is default if (ts == TS_Tone) return str; static QMap toneTable; // {ā, a1} initToneTable(toneTable); QString newStr = str; QString cv; for (QChar c : str) { if (!toneTable.contains(c)) continue; cv = toneTable.value(c); switch (ts) { case TS_NoneTone: newStr.replace(c, cv.left(1)); break; case TS_ToneNum: newStr.replace(c, cv); break; default: break; } } return newStr; } static QStringList toned(const QStringList &words, ToneStyle ts) { QStringList tonedWords; for (auto str : words) tonedWords << toned(str, ts); return tonedWords; } static QStringList permutations(const QStringList &list1, const QStringList &list2) { QStringList ret; for (const QString &str1 : list1) for (const QString &str2 : list2) ret << str1 + str2; return ret; } static QStringList permutations(const QList &pyList) { QStringList result; if (pyList.size() <= 1) return pyList.value(0, result); result = permutations(pyList.value(0), pyList.value(1)); for (int i = 2; i < pyList.size(); ++i) { result = permutations(result, pyList.value(i)); // 限制返回的大小, if (result.size() > 0xFFFF) { qWarning() << "Warning: Too many combinations have exceeded the limit\n"; break; } } return result; } static QStringList deduplication(const QStringList &list) { QStringList result; for (const QString &item : list) if (!result.contains(item)) result.append(item); return result; } /*! \fn QString Dtk::Core::Chinese2Pinyin(const QString &words) \brief Convert Chinese characters to Pinyin \note this function not support polyphonic characters support. \return pinyin of the words \sa Dtk::Core::pinyin */ QString Chinese2Pinyin(const QString &words) { QStringList res = pinyin(words, TS_ToneNum); return res.value(0); } /*! * @~english \enum Dtk::Core::ToneStyle pinyin tone style \value TS_NoneTone pinyin without tone \value TS_Tone pinyin with tone, default style in dictory file \value TS_ToneNum pinyin tone number */ /*! \fn QStringList Dtk::Core::pinyin(const QString &words, ToneStyle ts, bool *ok) \brief Convert Chinese characters to Pinyin with polyphonic characters support. \return pinyin list of the words */ QStringList pinyin(const QString &words, ToneStyle ts, bool *ok) { if (words.length() < 1) return QStringList(); InitDict(); if (ok) *ok = true; QList pyList; for (int i = 0; i < words.length(); ++i) { const uint key = words.at(i).unicode(); auto find_result = dict.find(key); if (find_result != dict.end()) { const QString &ret = find_result.value(); pyList << toned(ret.split(","), ts); } else { pyList << QStringList(words.at(i)); // 部分字没有在词典中找到,使用字本身, ok 可以判断结果 if (ok) *ok = false; } } return deduplication(permutations(pyList)); } /*! \fn QStringList Dtk::Core::firstLetters(const QString &words) \brief Convert Chinese characters to Pinyin firstLetters list \brief with polyphonic characters support. \return pinyin first letters list of the words */ QStringList firstLetters(const QString &words) { QList result; bool ok = false; for (const QChar &w : words) { QStringList pys = pinyin(w, TS_Tone, &ok); if (!ok) { result << QStringList(w); continue; } for (QString &py : pys) py = py.left(1); result << pys; } return deduplication(permutations(result)); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/drecentmanager.cpp000066400000000000000000000167541476226660600205240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "drecentmanager.h" #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) #include #endif DCORE_BEGIN_NAMESPACE #define RECENT_PATH QDir::homePath() + "/.local/share/recently-used.xbel" /*! \class Dtk::Core::DRecentManager \inmodule dtkcore \brief DRecentManager 是用来管理最近文件列表的类,提供了添加与删除文件项. 遵循 freedesktop 标准,在本地 share 目录存放,文件名为: recently-used.xbel,所以每个用户都有不同的列表。 该类的存在就是为 deepin 应用提供一个工具类,方便让打开的文件添加到最近文件列表中。 \sa Dtk::Core::DRecentData */ /*! \class Dtk::Core::DRecentData \inmodule dtkcore \brief 文件信息结构体. \table \row \li appName \li 应用名称 \row \li appExec \li 应用命令行名称 \row \li mimeType \li 文件 mimetype 名称,一般不需要填写,DRecentManager 内部自动获取 \endtable \sa Dtk::Core::DRecentManager */ /*! \brief DRecentManager::addItem 在最近列表中添加一个项. \a uri 文件路径 \a data 数据信息 \return 如果返回 true 则成功添加,false 为添加失败 */ bool DRecentManager::addItem(const QString &uri, DRecentData &data) { if (!QFileInfo(uri).exists() || uri.isEmpty()) { return false; } QFile file(RECENT_PATH); file.open(QIODevice::ReadWrite | QIODevice::Text); QString dateTime = QDateTime::currentDateTime().toTimeSpec(Qt::OffsetFromUTC).toString(Qt::ISODate); QDomDocument doc; if (!doc.setContent(&file)) { doc.clear(); doc.appendChild(doc.createProcessingInstruction("xml","version=\'1.0\' encoding=\'utf-8\'")); QDomElement xbelEle = doc.createElement("xbel"); xbelEle.setAttribute("xmlns:mime", "http://www.freedesktop.org/standards/shared-mime-info"); xbelEle.setAttribute("version", "1.0"); xbelEle.setAttribute("xmlns:bookmark", "http://www.freedesktop.org/standards/desktop-bookmarks"); doc.appendChild(xbelEle); } file.close(); // need to add file:// protocol. QUrl url = QUrl::fromLocalFile(uri); // get the MimeType name of the file. if (data.mimeType.isEmpty()) { data.mimeType = QMimeDatabase().mimeTypeForFile(uri).name(); } QDomElement rootEle = doc.documentElement(); QDomNodeList nodeList = rootEle.elementsByTagName("bookmark"); QDomElement bookmarkEle; bool isFound = false; // find bookmark element exists. for (int i = 0; i < nodeList.size(); ++i) { const QString fileUrl = nodeList.at(i).toElement().attribute("href"); if (fileUrl == url.toEncoded(QUrl::FullyDecoded)) { bookmarkEle = nodeList.at(i).toElement(); isFound = true; break; } } // update element content. if (isFound) { QDomNodeList appList = bookmarkEle.elementsByTagName("bookmark:application"); QDomElement appEle; bool appExists = false; for (int i = 0; i < appList.size(); ++i) { appEle = appList.at(i).toElement(); if (appEle.attribute("name") == data.appName && appEle.attribute("exec") == data.appExec) { appExists = true; break; } } if (appExists) { int count = appEle.attribute("count").toInt() + 1; bookmarkEle.setAttribute("modified", dateTime); bookmarkEle.setAttribute("visited", dateTime); appEle.setAttribute("modified", dateTime); appEle.setAttribute("count", QString::number(count)); } else { QDomNode appsNode = bookmarkEle.elementsByTagName("bookmark:applications").at(0); appEle = doc.createElement("bookmark:application"); appEle.setAttribute("name", data.appName); appEle.setAttribute("exec", data.appExec); appEle.setAttribute("modified", dateTime); appEle.setAttribute("count", "1"); appsNode.toElement().appendChild(appEle); } } // add new elements if they don't exist. else { QDomElement bookmarkEle, infoEle, metadataEle, mimeEle, appsEle, appChildEle; QString hrefStr = url.toEncoded(QUrl::FullyEncoded); bookmarkEle = doc.createElement("bookmark"); bookmarkEle.setAttribute("href", hrefStr); bookmarkEle.setAttribute("added", dateTime); bookmarkEle.setAttribute("modified", dateTime); bookmarkEle.setAttribute("visited", dateTime); infoEle = doc.createElement("info"); bookmarkEle.appendChild(infoEle); metadataEle = doc.createElement("metadata"); metadataEle.setAttribute("owner", "http://freedesktop.org"); infoEle.appendChild(metadataEle); mimeEle = doc.createElement("mime:mime-type"); mimeEle.setAttribute("type", data.mimeType); metadataEle.appendChild(mimeEle); appsEle = doc.createElement("bookmark:applications"); appChildEle = doc.createElement("bookmark:application"); appChildEle.setAttribute("name", data.appName); appChildEle.setAttribute("exec", data.appExec); appChildEle.setAttribute("modified", dateTime); appChildEle.setAttribute("count", "1"); appsEle.appendChild(appChildEle); metadataEle.appendChild(appsEle); QDomNode result = rootEle.appendChild(bookmarkEle); if (result.isNull()) { return false; } } // write to file. if (!file.open(QIODevice::WriteOnly)) { return false; } QTextStream out(&file); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) out.setEncoding(QStringConverter::Utf8); #else out.setCodec("UTF-8"); #endif out << doc.toString(); out.flush(); file.close(); return true; } /*! \brief DRecentManager::removeItem 在最近列表中移除单个文件路径 \a target 需要移除的文件路径 */ void DRecentManager::removeItem(const QString &target) { removeItems(QStringList() << target); } /*! \brief DRecentManager::removeItem 在最近列表中移除多个文件路径 \a list 需要移除的文件路径列表 */ void DRecentManager::removeItems(const QStringList &list) { QFile file(RECENT_PATH); if (!file.open(QIODevice::ReadOnly)) { return; } QDomDocument doc; if (!doc.setContent(&file)) { file.close(); return; } file.close(); QDomElement rootEle = doc.documentElement(); QDomNodeList nodeList = rootEle.elementsByTagName("bookmark"); for (int i = 0; i < nodeList.count(); ) { const QString fileUrl = nodeList.at(i).toElement().attribute("href"); if (list.contains(QUrl::fromPercentEncoding(fileUrl.toLatin1())) || list.contains(QUrl(fileUrl).toEncoded(QUrl::FullyDecoded))) { rootEle.removeChild(nodeList.at(i)); } else { ++i; } } if (!file.open(QIODevice::WriteOnly)) { return; } QTextStream out(&file); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) out.setEncoding(QStringConverter::Utf8); #else out.setCodec("UTF-8"); #endif out << doc.toString(); out.flush(); file.close(); return; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dtextencoding.cpp000066400000000000000000000340101476226660600203650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtextencoding.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #else #include #endif #include #include #include #include DCORE_BEGIN_NAMESPACE class LibICU { public: LibICU(); ~LibICU(); bool isValid(); bool detectEncoding(const QByteArray &content, QByteArrayList &charset); UCharsetDetector *(*icu_ucsdet_open)(UErrorCode *status); void (*icu_ucsdet_close)(UCharsetDetector *ucsd); void (*icu_ucsdet_setText)(UCharsetDetector *ucsd, const char *textIn, int32_t len, UErrorCode *status); const UCharsetMatch **(*icu_ucsdet_detectAll)(UCharsetDetector *ucsd, int32_t *matchesFound, UErrorCode *status); const char *(*icu_ucsdet_getName)(const UCharsetMatch *ucsm, UErrorCode *status); int32_t (*icu_ucsdet_getConfidence)(const UCharsetMatch *ucsm, UErrorCode *status); private: QLibrary *icuuc = nullptr; Q_DISABLE_COPY(LibICU) }; class Libuchardet { public: Libuchardet(); ~Libuchardet(); bool isValid(); QByteArray detectEncoding(const QByteArray &content); uchardet_t (*uchardet_new)(void); void (*uchardet_delete)(uchardet_t ud); int (*uchardet_handle_data)(uchardet_t ud, const char *data, size_t len); void (*uchardet_data_end)(uchardet_t ud); void (*uchardet_reset)(uchardet_t ud); const char *(*uchardet_get_charset)(uchardet_t ud); private: QLibrary *uchardet = nullptr; Q_DISABLE_COPY(Libuchardet) }; Q_GLOBAL_STATIC(LibICU, LibICUInstance); Q_GLOBAL_STATIC(Libuchardet, LibuchardetInstance); LibICU::LibICU() { // Load libicuuc.so icuuc = new QLibrary("libicuuc"); if (!icuuc->load()) { delete icuuc; icuuc = nullptr; return; } auto initFunctionError = [this]() { icuuc->unload(); delete icuuc; icuuc = nullptr; }; #define INIT_ICUUC(Name) \ icu_##Name = reinterpret_cast(icuuc->resolve(#Name)); \ if (!icu_##Name) { \ initFunctionError(); \ return; \ } // Note: use prefix 'icu' to avoid "disabled expansion of recursive macro" warning. INIT_ICUUC(ucsdet_open); INIT_ICUUC(ucsdet_close); INIT_ICUUC(ucsdet_setText); INIT_ICUUC(ucsdet_detectAll); INIT_ICUUC(ucsdet_getName); INIT_ICUUC(ucsdet_getConfidence); } LibICU::~LibICU() { if (icuuc) { delete icuuc; } } bool LibICU::isValid() { return (icuuc); } bool LibICU::detectEncoding(const QByteArray &content, QByteArrayList &charset) { UErrorCode status = U_ZERO_ERROR; UCharsetDetector *detector = icu_ucsdet_open(&status); if (U_FAILURE(status)) { return false; } icu_ucsdet_setText(detector, content.data(), content.size(), &status); if (U_FAILURE(status)) { icu_ucsdet_close(detector); return false; } int32_t matchCount = 0; const UCharsetMatch **charsetMatch = icu_ucsdet_detectAll(detector, &matchCount, &status); if (U_FAILURE(status)) { icu_ucsdet_close(detector); return false; } int recordCount = qMin(3, matchCount); for (int i = 0; i < recordCount; i++) { const char *encoding = icu_ucsdet_getName(charsetMatch[i], &status); if (U_FAILURE(status)) { icu_ucsdet_close(detector); return false; } charset << QByteArray(encoding); } icu_ucsdet_close(detector); return true; } Libuchardet::Libuchardet() { uchardet = new QLibrary("libuchardet", "0"); if (!uchardet->load()) { delete uchardet; uchardet = nullptr; return; } auto initFunctionError = [this]() { uchardet->unload(); delete uchardet; uchardet = nullptr; }; #define INIT_UCHARDET(Name) \ Name = reinterpret_cast(uchardet->resolve(#Name)); \ if (!Name) { \ initFunctionError(); \ return; \ } INIT_UCHARDET(uchardet_new); INIT_UCHARDET(uchardet_delete); INIT_UCHARDET(uchardet_handle_data); INIT_UCHARDET(uchardet_data_end); INIT_UCHARDET(uchardet_reset); INIT_UCHARDET(uchardet_get_charset); } Libuchardet::~Libuchardet() { if (uchardet) { delete uchardet; } } bool Libuchardet::isValid() { return uchardet; } QByteArray Libuchardet::detectEncoding(const QByteArray &content) { QByteArray charset; uchardet_t handle = uchardet_new(); if (0 == uchardet_handle_data(handle, content.data(), static_cast(content.size()))) { uchardet_data_end(handle); charset = QByteArray(uchardet_get_charset(handle)); } uchardet_delete(handle); return charset; } QByteArray selectCharset(const QByteArray &charset, const QByteArrayList &icuCharsetList) { if (icuCharsetList.isEmpty()) { return charset; } static QByteArray encodingGB18030("GB18030"); if (charset.isEmpty()) { return icuCharsetList.contains(encodingGB18030) ? encodingGB18030 : icuCharsetList[0]; } else { if (charset.contains(icuCharsetList[0])) { return charset; } else { return icuCharsetList[0].contains(charset) ? icuCharsetList[0] : charset; } } } QByteArray DTextEncoding::detectTextEncoding(const QByteArray &content) { if (content.isEmpty()) { return QByteArray("UTF-8"); } QByteArray charset; if (LibuchardetInstance()->isValid()) { charset = LibuchardetInstance()->detectEncoding(content); } if (LibICUInstance()->isValid()) { QByteArrayList icuCharsetList; if (LibICUInstance()->detectEncoding(content, icuCharsetList)) { if (charset.isEmpty() && !icuCharsetList.isEmpty()) { charset = icuCharsetList.first(); } else { // Improve GB18030 encoding recognition rate. charset = selectCharset(charset, icuCharsetList); } } } if (charset.isEmpty()) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) std::optional encoding = QStringConverter::encodingForData(content); if (encoding) { return QStringConverter::nameForEncoding(encoding.value()); } #else QTextCodec *codec = QTextCodec::codecForUtfText(content); if (codec) { return codec->name(); } #endif } // Use default encoding. if (charset.isEmpty() || charset.contains("ASCII")) { charset = QByteArray("UTF-8"); } return charset; } QByteArray DTextEncoding::detectFileEncoding(const QString &fileName, bool *isOk) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { if (isOk) { *isOk = false; } return QByteArray(); } // At most 64Kb data. QByteArray content = file.read(qMin(static_cast(file.size()), USHRT_MAX)); file.close(); if (isOk) { *isOk = true; } return detectTextEncoding(content); } bool DTextEncoding::convertTextEncoding( QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) { return convertTextEncodingEx(content, outContent, toEncoding, fromEncoding, errString); } bool DTextEncoding::convertTextEncodingEx(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString, int *convertedBytes) { if (content.isEmpty() || fromEncoding == toEncoding) { return true; } if (toEncoding.isEmpty()) { if (errString) { *errString = QStringLiteral("The encode that convert to is empty."); } return false; } QByteArray contentEncoding = fromEncoding; if (contentEncoding.isEmpty()) { contentEncoding = detectTextEncoding(content); } // iconv set errno when failed. iconv_t handle = iconv_open(toEncoding.data(), contentEncoding.data()); if (reinterpret_cast(-1) != handle) { size_t inBytesLeft = static_cast(content.size()); char *inbuf = content.data(); size_t outBytesLeft = inBytesLeft * 4; char *outbuf = new char[outBytesLeft]; char *bufferHeader = outbuf; size_t maxBufferSize = outBytesLeft; size_t ret = iconv(handle, &inbuf, &inBytesLeft, &outbuf, &outBytesLeft); int convertError = 0; if (static_cast(-1) == ret) { convertError = errno; int converted = content.size() - static_cast(inBytesLeft); if (convertedBytes) { *convertedBytes = converted; } if (errString) { switch (convertError) { case EILSEQ: *errString = QString("An invalid multibyte sequence has been encountered in the input." "Converted byte index: %1") .arg(converted); break; case EINVAL: *errString = QString("An incomplete multibyte sequence has been encountered in the input. " "Converted byte index: %1") .arg(converted); break; case E2BIG: *errString = QString("There is not sufficient room at *outbuf. Converted byte index: %1").arg(converted); break; default: break; } } } iconv_close(handle); // Use iconv converted byte count. size_t realConvertSize = maxBufferSize - outBytesLeft; outContent = QByteArray(bufferHeader, static_cast(realConvertSize)); delete[] bufferHeader; // For errors, user decides to keep or remove converted text. return 0 == convertError; } else { if (EINVAL == errno && errString) { *errString = QStringLiteral("The conversion from fromcode to tocode is not supported by the implementation."); } return false; } } bool DTextEncoding::convertFileEncoding(const QString &fileName, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) { if (fromEncoding == toEncoding) { return true; } QFile file(fileName); if (!file.open(QFile::ReadWrite | QFile::Text)) { if (errString) { *errString = file.errorString(); file.error(); } return false; } QByteArray content = file.readAll(); QByteArray outContent; if (!convertTextEncoding(content, outContent, toEncoding, fromEncoding, errString)) { file.close(); return false; } file.seek(0); file.write(outContent); file.resize(outContent.size()); file.close(); if (QFile::NoError != file.error()) { if (errString) { *errString = file.errorString(); } return false; } return true; } bool DTextEncoding::convertFileEncodingTo(const QString &fromFile, const QString &toFile, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) { if (fromEncoding == toEncoding) { return true; } if (fromFile == toFile) { return convertFileEncoding(fromFile, toEncoding, fromEncoding, errString); } // Check from file and to file before convert. QFile readFile(fromFile); if (!readFile.open(QFile::ReadOnly | QFile::Text)) { if (errString) { *errString = QString("Open convert from file failed, %1").arg(readFile.errorString()); } return false; } QFile writeFile(toFile); if (!writeFile.open(QFile::WriteOnly | QFile::Text)) { readFile.close(); if (errString) { *errString = QString("Open convert to file failed, %1").arg(writeFile.errorString()); } return false; } QByteArray content = readFile.readAll(); readFile.close(); QByteArray outContent; if (!convertTextEncoding(content, outContent, toEncoding, fromEncoding, errString)) { writeFile.close(); writeFile.remove(); return false; } writeFile.write(outContent); writeFile.close(); if (QFile::NoError != writeFile.error()) { if (errString) { *errString = writeFile.errorString(); } return false; } return true; } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dthreadutils.cpp000066400000000000000000000053511476226660600202300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2020 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dthreadutils.h" DCORE_BEGIN_NAMESPACE #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) namespace DThreadUtil { FunctionCallProxy::FunctionCallProxy(QThread *thread) { qRegisterMetaType>(); connect(this, &FunctionCallProxy::callInLiveThread, this, [] (QSemaphore *s, QPointer target, FunctionType *func) { if (Q_LIKELY(target)) { (*func)(); } else { qWarning() << "DThreadUtils::runInThread:" << "The target object is destoryed"; } s->release(); }, Qt::QueuedConnection); connect(thread, &QThread::finished, this, [this] { qWarning() << "DThreadUtils::runInThread:" << sender() << "the thread finished"; }, Qt::DirectConnection); } void FunctionCallProxy::proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun) { if (QThread::currentThread() == thread) return fun(); FunctionCallProxy proxy(thread); proxy.moveToThread(thread); // 如果线程未开启事件循环,且不是主线程,则需要给出严重警告信息,因为可能会导致死锁 if (thread->loopLevel() <= 0 && (!QCoreApplication::instance() || thread != QCoreApplication::instance()->thread())) { qCritical() << Q_FUNC_INFO << thread << ", the thread no event loop"; } proxy.callInLiveThread(s, target ? target : &proxy, &fun); s->acquire(); } } #else class Q_DECL_HIDDEN Caller : public QObject { public: explicit Caller() : QObject() { } bool event(QEvent *event) override { if (event->type() == DThreadUtils::eventType) { auto ev = static_cast(event); ev->call(); return true; } return QObject::event(event); } }; DThreadUtils::DThreadUtils(QThread *thread) : m_thread(thread) , threadContext(nullptr) { } DThreadUtils::~DThreadUtils() { delete threadContext.loadRelaxed(); } DThreadUtils &DThreadUtils::gui() { static auto global = DThreadUtils(QCoreApplication::instance()->thread()); return global; } QThread *DThreadUtils::thread() const noexcept { return m_thread; } QObject *DThreadUtils::ensureThreadContextObject() { QObject *context; if (!threadContext.loadRelaxed()) { context = new Caller(); context->moveToThread(m_thread); if (!threadContext.testAndSetRelaxed(nullptr, context)) { context->moveToThread(nullptr); delete context; } } context = threadContext.loadRelaxed(); Q_ASSERT(context); return context; } #endif DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dtimedloop.cpp000066400000000000000000000071271476226660600176770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtimedloop.h" #include #include #include #include #include #include DCORE_BEGIN_NAMESPACE #ifdef QT_DEBUG Q_LOGGING_CATEGORY(logTimedLoop, "dtk.dtimedloop") #else Q_LOGGING_CATEGORY(logTimedLoop, "dtk.dtimedloop", QtInfoMsg) #endif class DTimedLoopPrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DTimedLoop) public: DTimedLoopPrivate(DTimedLoop *qq = nullptr); ~DTimedLoopPrivate(); int m_returnCode = 0; QTime m_startTime; QTime m_stopTime; bool m_timeDumpFlag = false; char __padding[3]; QString m_exectionName; void setExecutionName(const QString &executionName); class LoopGuard { DTimedLoopPrivate *m_p = nullptr; public: LoopGuard(DTimedLoopPrivate *p) : m_p (p) { m_p->m_startTime = QTime::currentTime(); } ~LoopGuard() { m_p->m_stopTime = QTime::currentTime(); if (!m_p->m_timeDumpFlag) { return; } if (Q_UNLIKELY(m_p->m_exectionName.isEmpty())) { qCDebug(logTimedLoop(), "The execution time is %-5d ms", m_p->m_startTime.msecsTo(QTime::currentTime())); } else { qCDebug(logTimedLoop(), "The execution time is %-5d ms for \"%s\"", m_p->m_startTime.msecsTo(QTime::currentTime()), m_p->m_exectionName.toLocal8Bit().data()); m_p->m_exectionName.clear(); } } }; }; DTimedLoopPrivate::DTimedLoopPrivate(DTimedLoop *qq) : DObjectPrivate (qq) { } DTimedLoopPrivate::~DTimedLoopPrivate() { } void DTimedLoopPrivate::setExecutionName(const QString &executionName) { m_exectionName = executionName; } DTimedLoop::DTimedLoop(QObject *parent) noexcept : QEventLoop (parent) , DObject (*new DTimedLoopPrivate(this)) { } DTimedLoop::DTimedLoop() noexcept : QEventLoop () , DObject (*new DTimedLoopPrivate(this)) { } DTimedLoop::~DTimedLoop() { } int DTimedLoop::runningTime() { Q_D(DTimedLoop); if (QEventLoop::isRunning()) { return d->m_startTime.msecsTo(QTime::currentTime()); } return d->m_startTime.msecsTo(d->m_stopTime); } void DTimedLoop::setTimeDump(bool flag) { Q_D(DTimedLoop); d->m_timeDumpFlag = flag; } void DTimedLoop::exit(int returnCode) { // 避免在子线程中提前被执行 DThreadUtil::runInMainThread([this, returnCode]{ QEventLoop::exit(returnCode); }); } int DTimedLoop::exec(QEventLoop::ProcessEventsFlags flags) { Q_D(DTimedLoop); DTimedLoopPrivate::LoopGuard guard(d); return QEventLoop::exec(flags); } int DTimedLoop::exec(int durationTimeMs, QEventLoop::ProcessEventsFlags flags) { Q_D(DTimedLoop); int runningTime = durationTimeMs < 0 ? 0 : durationTimeMs; QTimer::singleShot(runningTime, [this] { QEventLoop::exit(0); }); DTimedLoopPrivate::LoopGuard guard(d); return QEventLoop::exec(flags); } int DTimedLoop::exec(const QString &executionName, QEventLoop::ProcessEventsFlags flags) { Q_D(DTimedLoop); d->setExecutionName(executionName); return exec(flags); } int DTimedLoop::exec(int durationMs, const QString &executionName, QEventLoop::ProcessEventsFlags flags) { Q_D(DTimedLoop); d->setExecutionName(executionName); return exec(durationMs, flags); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dtimeunitformatter.cpp000066400000000000000000000016361476226660600214640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtimeunitformatter.h" #include DCORE_BEGIN_NAMESPACE DTimeUnitFormatter::DTimeUnitFormatter() : DAbstractUnitFormatter() { } uint DTimeUnitFormatter::unitConvertRate(int unitId) const { switch (unitId) { case Seconds: return 60; case Minute: return 60; case Hour: return 24; default:; } return 0; } QString DTimeUnitFormatter::unitStr(int unitId) const { switch (unitId) { case Seconds: return QStringLiteral("s"); case Minute: return QStringLiteral("m"); case Hour: return QStringLiteral("h"); case Day: return QStringLiteral("d"); default:; } return QString(); } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/dvtablehook.cpp000066400000000000000000000335321476226660600200400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dvtablehook.h" #include #include #ifdef Q_OS_LINUX #include #include #include QT_BEGIN_NAMESPACE QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); QT_END_NAMESPACE #endif DCORE_BEGIN_NAMESPACE QMap DVtableHook::objToOriginalVfptr; QMap DVtableHook::objToGhostVfptr; QMap DVtableHook::objDestructFun; bool DVtableHook::copyVtable(quintptr **obj) { int vtable_size = getVtableSize(obj); if (vtable_size == 0) return false; // 多开辟一个元素, 新的虚表结构如下: // 假设原虚表内存布局如下(考虑多继承): // C Vtable (7 entities) // +--------------------+ // struct C | offset_to_top (0) | // object +--------------------+ // 0 - struct A (primary base) | RTTI for C | // 0 - vptr_A -----------------------------> +--------------------+ // 8 - int ax | C::f0() | // 16 - struct B +--------------------+ // 16 - vptr_B ----------------------+ | C::f1() | // 24 - int bx | +--------------------+ // 28 - int cx | | offset_to_top (-16)| // sizeof(C): 32 align: 8 | +--------------------+ // | | RTTI for C | // +------> +--------------------+ // | Thunk C::f1() | // +--------------------+ // 则新的表结构为: // C Vtable (7 entities) C hooked Vtable (7 entities) // +--------------------+ +--------------------+ // struct C | offset_to_top (0) | | offset_to_top (0) | // object +--------------------+ +--------------------+ // 0 - struct A (primary base) | RTTI for C | | RTTI for C | // 0 - vptr_A -----------------------------// +--------------------+ //------> +--------------------+ // 8 - int ax | C::f0() |\ | C::f0() | (or override custom function pointer) // 16 - struct B +--------------------+ \ +--------------------+ // 16 - vptr_B ----------------------+ | C::f1() | \ | C::f1() | (or override custom function pointer) // 24 - int bx | +--------------------+ \ +--------------------+ // 28 - int cx | | offset_to_top (-16)| \ | offset_to_top (-16)| // sizeof(C): 32 align: 8 | +--------------------+ \ +--------------------+ // | | RTTI for C | + | RTTI for C | // +------> +--------------------+ | +--------------------+ // | Thunk C::f1() | | | Thunk C::f1() | // +--------------------+ | +--------------------+ // | | 0 | // | +--------------------+ // +----| original entry | // +--------------------+ quintptr *new_vtable = new quintptr[vtable_size + 2]; // store 0 and oringinal entry memcpy(new_vtable, adjustToTop(*obj), vtable_size * sizeof(quintptr)); new_vtable[vtable_size] = 0; //! save original vfptr objToOriginalVfptr[obj] = *obj; // 存储对象原虚表入口地址 new_vtable[vtable_size + 1] = quintptr(*obj); *obj = adjustToEntry(new_vtable); //! save ghost vfptr objToGhostVfptr[obj] = new_vtable; return true; } bool DVtableHook::clearGhostVtable(const void *obj) { if (!objToOriginalVfptr.remove((quintptr **)obj)) // Uninitialized memory may have values, for resetVtable return false; objDestructFun.remove(obj); quintptr *vtable = objToGhostVfptr.take(obj); if (vtable) { delete[] vtable; return true; } return false; } /** \brief 通过遍历尝试找到析构函数在虚表中的位置 \a obj \a destoryObjFun \return */ int DVtableHook::getDestructFunIndex(quintptr **obj, std::function destoryObjFun) { class _DestoryProbe { public: static quintptr probe(quintptr obj) { static quintptr _obj = 0; if (obj == 0) { obj = _obj; _obj = 0; } else { _obj = obj; } return obj; } static void nothing() { } }; quintptr *vtable = *obj; int vtable_size = getVtableSize(obj); if (vtable_size == 0) return -1; quintptr *new_vtable = new quintptr[vtable_size]; std::fill(adjustToEntry(new_vtable), new_vtable + vtable_size, quintptr(&_DestoryProbe::nothing)); // 给对象设置新的虚表 *obj = adjustToEntry(new_vtable); int index = -1; for (int i = adjustToEntry(0); i < vtable_size; ++i) { new_vtable[i] = quintptr(&_DestoryProbe::probe); // 尝试销毁此对象, 且观察_DestoryProbe::probe是否被调用 // 如果被调用, 则证明覆盖此虚函数能达到监控对象被销毁的目的 destoryObjFun(); if (_DestoryProbe::probe(0) == quintptr(obj)) { index = adjustToTop(i); break; } } // 恢复旧的虚表 *obj = vtable; // 销毁临时虚表 delete[] new_vtable; return index; } void DVtableHook::autoCleanVtable(const void *obj) { quintptr fun = objDestructFun.value(obj); if (!fun) return; if (hasVtable(obj)) {// 需要判断一下,有可能在执行析构函数时虚表已经被删除 // clean clearGhostVtable(obj); } typedef void(*Destruct)(const void*); Destruct destruct = reinterpret_cast(fun); // call origin destruct function destruct(obj); } bool DVtableHook::ensureVtable(const void *obj, std::function destoryObjFun) { quintptr **_obj = (quintptr**)(obj); if (objToOriginalVfptr.contains(_obj)) { // 不知道什么原因, 此时obj对象的虚表已经被还原 if (objToGhostVfptr.value((void *)obj) != adjustToTop(*_obj)) { clearGhostVtable((void*)obj); } else { return true; } } if (!copyVtable(_obj)) return false; // 查找对象的析构函数 int index = getDestructFunIndex(_obj, destoryObjFun); // 虚析构函数查找失败 if (index < 0) { qCWarning(vtableHook) << "Failed do override destruct function: " << obj; abort(); } quintptr *new_vtable = *_obj; // 保存对象真实的析构函数 objDestructFun[(void*)obj] = new_vtable[index]; // 覆盖析构函数, 用于在对象析构时自动清理虚表 new_vtable[index] = reinterpret_cast(&autoCleanVtable); return true; } /*! \brief DVtableHook::hasVtable 对象的虚表已经被覆盖时返回true,否则返回false \a obj \return */ bool DVtableHook::hasVtable(const void *obj) { quintptr **_obj = (quintptr**)(obj); return objToGhostVfptr.contains(_obj); } void DVtableHook::resetVtable(const void *obj) { quintptr **_obj = (quintptr**)obj; int vtable_size = getVtableSize(_obj); // 获取obj对象原本虚表的入口 auto vtableHead = adjustToTop(*_obj); quintptr *vfptr_t2 = (quintptr*)vtableHead[vtable_size + 1]; // _obj - 2 + vtable_size + 1 if (!vfptr_t2) return; if (!clearGhostVtable(obj)) return; // 还原虚表 *_obj = vfptr_t2; } /*! \brief 将偏移量为\a functionOffset 的虚函数还原到原本的实现 \a obj \a functionOffset \return 如果成功, 返回还原之前obj对象虚表中存储的函数指针, 否则返回0 */ quintptr DVtableHook::resetVfptrFun(const void *obj, quintptr functionOffset) { quintptr *vfptr_t1 = *(quintptr **)obj; quintptr current_fun = *(vfptr_t1 + functionOffset / sizeof(quintptr)); quintptr origin_fun = originalFun(obj, functionOffset); if (!origin_fun) { return 0; } // reset to original fun *(vfptr_t1 + functionOffset / sizeof(quintptr)) = origin_fun; return current_fun; } /*! \brief 获取 \a obj 对象偏移量为 \a functionOffset 的虚函数原本的函数指针 \return 如果obj对象虚表没有被覆盖, 或者函数偏移量正确, 将返回0 */ quintptr DVtableHook::originalFun(const void *obj, quintptr functionOffset) { quintptr **_obj = (quintptr **)obj; if (!hasVtable(obj)) { qCWarning(vtableHook) << "Not override the object virtual table: " << obj; return 0; } int vtable_size = getVtableSize(_obj); // 获取obj对象原本虚表的入口 quintptr *vfptr_t2 = (quintptr*)(*_obj)[vtable_size - 1]; if (functionOffset > UINT_LEAST16_MAX) { qCWarning(vtableHook, "Is not a virtual function, function address: 0X%llx", functionOffset); return 0; } return *(vfptr_t2 + functionOffset / sizeof(quintptr)); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) bool DVtableHook::isFinalClass(quintptr *obj) { Q_UNUSED(obj); return true; } quintptr **DVtableHook::adjustThis(quintptr *obj) { Q_UNUSED(obj); return nullptr; } #endif #if defined(Q_OS_LINUX) static int readProtFromPsm(quintptr adr, size_t length) { int prot = PROT_NONE; QString fname = "/proc/self/maps"; QFile f(fname); if (!f.open(QIODevice::ReadOnly)) { qFatal("%s", f.errorString().toStdString().data()); //return prot; // never be executed } QByteArray data = f.readAll(); bool ok = false; quintptr startAddr = 0, endAddr = 0; QTextStream ts(data); while (Q_UNLIKELY(!ts.atEnd())) { const QString line = ts.readLine(); const QStringList &maps = line.split(' '); if (Q_UNLIKELY(maps.size() < 3)) { data = f.readLine(); continue; } //"00400000-00431000" "r--p" const QStringList addrs = maps.value(0).split('-'); startAddr = addrs.value(0).toULongLong(&ok, 16); Q_ASSERT(ok); endAddr = addrs.value(1).toULongLong(&ok, 16); Q_ASSERT(ok); if (Q_LIKELY(adr >= endAddr)) { continue; } if (adr >= startAddr && adr + length <= endAddr) { QString ps = maps.value(1); //qDebug() << maps.value(0) << maps.value(1); for (QChar c : ps) { switch (c.toLatin1()) { case 'r': prot |= PROT_READ; break; case 'w': prot |= PROT_WRITE; break; case 'x': prot |= PROT_EXEC; break; default: break; // '-' 'p' don't care } } break; } else if (adr < startAddr) { qFatal("%p not found in proc maps", reinterpret_cast(adr)); //break; // 超出了地址不需要再去检查了 } } return prot; } #endif bool DVtableHook::forceWriteMemory(void *adr, const void *data, size_t length) { #ifdef Q_OS_LINUX int page_size = sysconf(_SC_PAGESIZE); quintptr x = reinterpret_cast(adr); // 不减去一个pagesize防止跨越两个数据区域(对应/proc/self/maps两行数据) void *new_adr = reinterpret_cast((x /*- page_size - 1*/) & ~(page_size - 1)); size_t override_data_length = length + x - reinterpret_cast(new_adr); int oldProt = readProtFromPsm(quintptr(new_adr), override_data_length); bool writeable = oldProt & PROT_WRITE; // 增加判断是否已经可写,不能写才调用。 // 失败时直接放弃 if (!writeable && mprotect(new_adr, override_data_length, PROT_READ | PROT_WRITE)) { qCWarning(vtableHook, "mprotect(change) failed: %s", strerror(errno)); return false; } #endif // 复制数据 memcpy(adr, data, length); #ifdef Q_OS_LINUX // 恢复内存标志位 if (!writeable && mprotect(new_adr, override_data_length, oldProt)) { qCWarning(vtableHook, "mprotect(restore) failed: %s", strerror(errno)); return false; } #endif return true; } QFunctionPointer DVtableHook::resolve(const char *symbol) { #ifdef Q_OS_LINUX /** !!不要使用qt_linux_find_symbol_sys函数去获取符号 在龙芯平台上,qt_linux_find_symbol_sys 无法获取部分已加载动态库的符号, 可能的原因是这个函数对 dlsym 的调用是在 libQt5Core 动态库中,这个库加载的比较早, 有可能是因此导致无法获取比这个库加载更晚的库中的符号(仅为猜测) */ return QFunctionPointer(dlsym(RTLD_DEFAULT, symbol)); #else // TODO return nullptr; #endif } DCORE_END_NAMESPACE dtkcore-5.7.12/src/util/resources/000077500000000000000000000000001476226660600170365ustar00rootroot00000000000000dtkcore-5.7.12/src/util/resources/dpinyin.dict000066400000000000000000017473071476226660600214000ustar00rootroot000000000000000x3400:qiū # 㐀 0x3401:tiǎn,tiàn # 㐁 0x3404:kuà # 㐄 0x3405:wǔ # 㐅 0x3406:yǐn,yī # 㐆 0x340c:sì,yí # 㐌 0x3416:yè # 㐖 0x341c:chóu # 㐜 0x3421:nuò # 㐡 0x3424:qiú # 㐤 0x3428:xù # 㐨 0x3429:xíng # 㐩 0x342b:xiōng # 㐫 0x342c:liú # 㐬 0x342d:lǐn # 㐭 0x342e:xiāng # 㐮 0x342f:yōng # 㐯 0x3430:xìn # 㐰 0x3431:zhěn # 㐱 0x3432:dài,fú # 㐲 0x3433:wù # 㐳 0x3434:pān # 㐴 0x3437:mǎ,mà,mián # 㐷 0x3438:qiàn # 㐸 0x3439:yì # 㐹 0x343a:zhòng,yín # 㐺 0x343b:nèi # 㐻 0x343c:chèng,zhěng # 㐼 0x3441:zhuō # 㑁 0x3442:fǎng,páng # 㑂 0x3443:ǎo # 㑃 0x3444:wǔ # 㑄 0x3445:zuò # 㑅 0x3447:zhòu # 㑇 0x3448:dòng # 㑈 0x3449:sù # 㑉 0x344a:yì # 㑊 0x344b:jiòng,kǒng,qióng # 㑋 0x344c:wāng,kuāng # 㑌 0x344d:lěi,lèi # 㑍 0x344e:nǎo # 㑎 0x344f:zhù # 㑏 0x3454:xǔ # 㑔 0x3458:jiè # 㑘 0x3459:dié,yǒng # 㑙 0x345a:nuó # 㑚 0x345b:sù # 㑛 0x345c:yì,chì # 㑜 0x345d:lòng # 㑝 0x345e:yìng # 㑞 0x345f:běng,bó,pěng # 㑟 0x3463:lán # 㑣 0x3464:miáo # 㑤 0x3465:yì # 㑥 0x3466:lì # 㑦 0x3467:jì # 㑧 0x3468:yǔ # 㑨 0x3469:luó # 㑩 0x346a:chái # 㑪 0x346e:hún,wén # 㑮 0x346f:xǔ # 㑯 0x3470:huì # 㑰 0x3471:rǎo # 㑱 0x3473:zhòu # 㑳 0x3475:hàn,jí,jié,zhǎ,zí # 㑵 0x3476:xì # 㑶 0x3477:tài # 㑷 0x3478:ǎi,yáo,yóu # 㑸 0x3479:huì # 㑹 0x347a:jùn # 㑺 0x347b:mà # 㑻 0x347c:lüè # 㑼 0x347d:táng # 㑽 0x347e:xiáo,yáo # 㑾 0x347f:zhào # 㑿 0x3480:zhǎ # 㒀 0x3481:yǔ,yùn # 㒁 0x3482:kù,zhuó # 㒂 0x3483:èr # 㒃 0x3484:nàng,nèn,rǎn # 㒄 0x3485:qǐ # 㒅 0x3486:chì,kè,xì,xiào,yàn # 㒆 0x3487:mù,wǔ # 㒇 0x3488:hàn # 㒈 0x3489:tǎng # 㒉 0x348a:sè # 㒊 0x348c:qióng # 㒌 0x348d:léi,lěi # 㒍 0x348e:sǎ,sà,tàn # 㒎 0x3491:huì,kuǐ # 㒑 0x3492:pú # 㒒 0x3493:tà # 㒓 0x3494:shǔ # 㒔 0x3496:ǒu # 㒖 0x3497:tái # 㒗 0x3499:mián # 㒙 0x349a:wěn # 㒚 0x349b:diào # 㒛 0x349c:yú,yǔ # 㒜 0x349d:miè,wà # 㒝 0x349e:jùn,kě # 㒞 0x349f:niǎo # 㒟 0x34a0:xiè # 㒠 0x34a1:yóu # 㒡 0x34a4:shè,chè # 㒤 0x34a6:lěi # 㒦 0x34a7:lì # 㒧 0x34a9:luǒ # 㒩 0x34ab:jì # 㒫 0x34b0:quán # 㒰 0x34b2:cái # 㒲 0x34b3:liǎng # 㒳 0x34b4:gǔ # 㒴 0x34b5:mào # 㒵 0x34b7:guǎ,xìng,xǔ # 㒷 0x34b8:suì,xuán # 㒸 0x34bb:mào # 㒻 0x34bc:mán # 㒼 0x34be:shì # 㒾 0x34bf:lí # 㒿 0x34c1:wǎng # 㓁 0x34c2:kòu # 㓂 0x34c3:chuí,dù,zhà # 㓃 0x34c4:zhèn # 㓄 0x34c8:bèi,bìng,fèi,yè # 㓈 0x34c9:huàn,huó,huò # 㓉 0x34ca:dòng # 㓊 0x34cb:gòng # 㓋 0x34ce:qīn,qǐn,qìn # 㓎 0x34cf:jiǒng # 㓏 0x34d0:lù # 㓐 0x34d1:xìng # 㓑 0x34d3:nán # 㓓 0x34d4:xiè # 㓔 0x34d6:bì,bié # 㓖 0x34d7:jié,qǐ # 㓗 0x34d8:sù # 㓘 0x34dc:yòu # 㓜 0x34dd:xíng # 㓝 0x34de:qì,qià,yáo # 㓞 0x34e0:diàn # 㓠 0x34e1:fǔ,fǒu # 㓡 0x34e2:luò # 㓢 0x34e3:qià # 㓣 0x34e4:jié,qià # 㓤 0x34e7:yǎn # 㓧 0x34e8:cí,cì # 㓨 0x34ea:lǎng # 㓪 0x34ed:hé # 㓭 0x34ef:lí # 㓯 0x34f0:huà # 㓰 0x34f1:tóu # 㓱 0x34f2:piàn # 㓲 0x34f4:jùn,ruǎn # 㓴 0x34f5:è # 㓵 0x34f6:qiè # 㓶 0x34f7:yì # 㓷 0x34f8:jué,zhuó # 㓸 0x34f9:ruì # 㓹 0x34fa:jiàn # 㓺 0x34fc:chì,chòng # 㓼 0x34fd:chóng # 㓽 0x34fe:chí # 㓾 0x3500:lüè,qíng # 㔀 0x3502:lín # 㔂 0x3503:jué,pì # 㔃 0x3504:sù # 㔄 0x3505:xiào # 㔅 0x3506:zàn # 㔆 0x3509:zhú # 㔉 0x350a:dǎn # 㔊 0x350b:jiàn,lán,làn # 㔋 0x350c:zhòu # 㔌 0x350d:duǒ,zhá # 㔍 0x350e:xiè,yì # 㔎 0x350f:lì # 㔏 0x3511:chì,dào,qì,shuì # 㔑 0x3512:xí # 㔒 0x3513:jiǎn,xiàn # 㔓 0x3515:jí,yì # 㔕 0x3517:fèi # 㔗 0x3518:chù # 㔘 0x3519:bǎng,péng # 㔙 0x351a:kǒu # 㔚 0x351c:bá,bó # 㔜 0x351d:liǎng # 㔝 0x351e:kuài,kuàng,wàng # 㔞 0x3520:hé,jiá # 㔠 0x3522:jué # 㔢 0x3523:léi,lèi # 㔣 0x3524:shěn # 㔤 0x3525:pí # 㔥 0x3526:yǎng # 㔦 0x3527:xuè # 㔧 0x3528:bèi # 㔨 0x3529:è # 㔩 0x352a:lǔ # 㔪 0x352d:chè,chí,yí # 㔭 0x352e:nuó # 㔮 0x352f:suǎn,xuán # 㔯 0x3530:héng # 㔰 0x3531:yǔ # 㔱 0x3533:guǐ,gùn,huán,jué # 㔳 0x3534:yì # 㔴 0x3535:xiàn,xuǎn # 㔵 0x3536:gòng # 㔶 0x3537:lòu # 㔷 0x3539:lè # 㔹 0x353a:shì # 㔺 0x353c:sǔn # 㔼 0x353d:yào,yǒu # 㔽 0x353e:jié # 㔾 0x353f:zòu # 㔿 0x3541:què # 㕁 0x3542:yín # 㕂 0x3544:zhì # 㕄 0x3545:jiǎ # 㕅 0x3546:hù # 㕆 0x3547:lá,lā # 㕇 0x3548:hòu,yǐ # 㕈 0x3549:kè # 㕉 0x354b:jìng,qín # 㕋 0x354c:ài # 㕌 0x354e:è,kè,kǔn # 㕎 0x354f:chú # 㕏 0x3550:xiě # 㕐 0x3551:chú # 㕑 0x3552:wéi,wěi,wēi # 㕒 0x3555:huàn # 㕕 0x3556:sù # 㕖 0x3557:yòu # 㕗 0x3559:jùn,ruì # 㕙 0x355a:zhǎo # 㕚 0x355b:xù,yǒu,yòu # 㕛 0x355c:shǐ # 㕜 0x355f:kuì # 㕟 0x3561:hé,hè,huò # 㕡 0x3562:gài,hài,jù,lǔn,nǒu # 㕢 0x3563:yǎn,yàn # 㕣 0x3564:qiú # 㕤 0x3565:yǐ # 㕥 0x3566:huà # 㕦 0x3568:fàn # 㕨 0x3569:zhàng # 㕩 0x356a:dǎn # 㕪 0x356b:fǎng # 㕫 0x356c:sòng # 㕬 0x356d:ào,bì # 㕭 0x356e:fǔ,tiào # 㕮 0x356f:nè # 㕯 0x3570:hè # 㕰 0x3571:yóu # 㕱 0x3572:huá,yíng # 㕲 0x3574:chén # 㕴 0x3575:guó,hún,luǒ # 㕵 0x3576:ň,ňg # 㕶 0x3577:huà # 㕷 0x3578:lì # 㕸 0x3579:fá # 㕹 0x357a:háo # 㕺 0x357b:tòu # 㕻 0x357d:sì # 㕽 0x3580:lè,luò # 㖀 0x3581:lìn # 㖁 0x3582:yì # 㖂 0x3583:hǒu,hòu # 㖃 0x3585:xù # 㖅 0x3586:qú,qǔ # 㖆 0x3587:ér # 㖇 0x358f:nèi # 㖏 0x3590:wěi # 㖐 0x3591:xiè # 㖑 0x3592:tí # 㖒 0x3593:hóng # 㖓 0x3594:tǔn # 㖔 0x3595:bò,niè # 㖕 0x3596:niè # 㖖 0x3597:yín # 㖗 0x359e:wāi # 㖞 0x359f:shòu # 㖟 0x35a0:bà,nuò # 㖠 0x35a1:yè # 㖡 0x35a2:jí,qí # 㖢 0x35a3:tòu # 㖣 0x35a4:hán # 㖤 0x35a5:jiǒng # 㖥 0x35a6:dǒng # 㖦 0x35a7:wěn # 㖧 0x35a8:lù # 㖨 0x35a9:sǒu # 㖩 0x35aa:guó # 㖪 0x35ab:líng # 㖫 0x35ad:tiǎn # 㖭 0x35ae:lún # 㖮 0x35b6:yè # 㖶 0x35b7:shí,tí # 㖷 0x35b8:xué # 㖸 0x35b9:fèn # 㖹 0x35ba:chǔn # 㖺 0x35bb:róu # 㖻 0x35bc:duǒ,lín,móu # 㖼 0x35bd:zé,zéi # 㖽 0x35be:è # 㖾 0x35bf:xié # 㖿 0x35c1:è # 㗁 0x35c2:shěng # 㗂 0x35c3:wěn,yìn # 㗃 0x35c4:mán,màn # 㗄 0x35c5:hú # 㗅 0x35c6:gé,kài # 㗆 0x35c7:xiá,ya # 㗇 0x35c8:màn # 㗈 0x35c9:bì,è,lüè # 㗉 0x35ca:jí,qì,bī,léi # 㗊 0x35cb:hóu # 㗋 0x35cc:zhì # 㗌 0x35d1:bài # 㗑 0x35d2:ài # 㗒 0x35d5:gòu # 㗕 0x35d6:dàn # 㗖 0x35d7:bǎi # 㗗 0x35d8:bó,fù # 㗘 0x35d9:nà,chú,zhōu # 㗙 0x35da:lì # 㗚 0x35db:xiào # 㗛 0x35dc:xiù # 㗜 0x35e2:dòng,hóng # 㗢 0x35e3:tì # 㗣 0x35e4:cù # 㗤 0x35e5:kuò # 㗥 0x35e6:láo # 㗦 0x35e7:zhì # 㗧 0x35e8:ǎi # 㗨 0x35e9:xī # 㗩 0x35eb:qiè # 㗫 0x35f0:chù,cóng # 㗰 0x35f1:jí # 㗱 0x35f2:huò,xì # 㗲 0x35f3:tǎ # 㗳 0x35f4:yán # 㗴 0x35f5:xù # 㗵 0x35f7:sǎi # 㗷 0x35fc:yè # 㗼 0x35fd:xiǎng # 㗽 0x35ff:hé,xià,xiā # 㗿 0x3600:zuò # 㘀 0x3601:yì # 㘁 0x3602:cí # 㘂 0x3605:xián # 㘅 0x3606:tái # 㘆 0x3607:róng # 㘇 0x3608:yī,yì # 㘈 0x3609:zhì # 㘉 0x360a:yì # 㘊 0x360b:xián # 㘋 0x360c:jù # 㘌 0x360d:jí,qì # 㘍 0x360e:hǎn,hàn # 㘎 0x3610:pào,pěng # 㘐 0x3611:lì # 㘑 0x3613:lán # 㘓 0x3614:cǎn,sǎi # 㘔 0x3615:hǎn,lán # 㘕 0x3616:yán # 㘖 0x3619:yán,yǎn # 㘙 0x361a:hǎn # 㘚 0x361c:chǐ,chóu,chù # 㘜 0x361d:niǎn,niè,nà,lǎn # 㘝 0x361e:huò # 㘞 0x3620:bì,mì # 㘠 0x3621:xiá # 㘡 0x3622:wěng # 㘢 0x3623:xuán,yuán # 㘣 0x3625:yóu # 㘥 0x3626:qín # 㘦 0x3627:xù # 㘧 0x3628:nèi # 㘨 0x3629:bì # 㘩 0x362a:hào # 㘪 0x362b:jǐng # 㘫 0x362c:ào # 㘬 0x362d:ào # 㘭 0x3632:jú # 㘲 0x3634:zuò # 㘴 0x3635:bù # 㘵 0x3636:jié # 㘶 0x3637:ài # 㘷 0x3638:zàng # 㘸 0x3639:cí # 㘹 0x363a:fá # 㘺 0x363f:niè # 㘿 0x3640:liù # 㙀 0x3641:mǎng,méi,mèi,mù,nà # 㙁 0x3642:duì # 㙂 0x3644:bì # 㙄 0x3645:bǎo # 㙅 0x3647:chù # 㙇 0x3648:hán,xià # 㙈 0x3649:tiǎn # 㙉 0x364a:cháng,zhàng # 㙊 0x364f:fù # 㙏 0x3650:duǒ # 㙐 0x3651:yǔ # 㙑 0x3652:yě # 㙒 0x3653:kuí # 㙓 0x3654:hán # 㙔 0x3655:kuài # 㙕 0x3657:kuài # 㙗 0x3659:lǒng # 㙙 0x365b:bǔ # 㙛 0x365c:chí,tái # 㙜 0x365d:xié # 㙝 0x365e:niè # 㙞 0x365f:lǎng # 㙟 0x3660:yì,yī # 㙠 0x3662:mán,mén # 㙢 0x3663:zhàng # 㙣 0x3664:xià # 㙤 0x3665:gǔn # 㙥 0x3668:jì,qí # 㙨 0x3669:liáo # 㙩 0x366a:yè,yì # 㙪 0x366b:jí # 㙫 0x366c:yín # 㙬 0x366e:dā,da # 㙮 0x366f:yì # 㙯 0x3670:xiè # 㙰 0x3671:hào # 㙱 0x3672:yǒng # 㙲 0x3673:hǎn,hé,kǎn # 㙳 0x3674:chàn,zhàn # 㙴 0x3675:tái # 㙵 0x3676:táng # 㙶 0x3677:zhí # 㙷 0x3678:bào,bó,pú # 㙸 0x3679:méng # 㙹 0x367a:guì,kuí # 㙺 0x367b:chán,qiè,zàn # 㙻 0x367c:lěi # 㙼 0x367e:xì,xué # 㙾 0x3681:qiáo,qiào,qù # 㚁 0x3682:ráng # 㚂 0x3683:yún,yùn,yūn # 㚃 0x3685:lóng # 㚅 0x3686:fù # 㚆 0x3689:gǔ # 㚉 0x368c:huà,huǒ # 㚌 0x368d:guó,kuǐ,kuì # 㚍 0x368f:gǎo # 㚏 0x3690:tào # 㚐 0x3692:shǎn # 㚒 0x3693:lái,lǎi # 㚓 0x3694:niè # 㚔 0x3695:fú,bì # 㚕 0x3696:gǎo # 㚖 0x3697:qié,xié # 㚗 0x3698:bàn # 㚘 0x369b:xì # 㚛 0x369c:xù,yù # 㚜 0x369d:kuí # 㚝 0x369e:měng,shěn,yìng,yùn # 㚞 0x369f:chuò # 㚟 0x36a1:jǐ # 㚡 0x36a2:nú # 㚢 0x36a3:jiāo,xiáo # 㚣 0x36a4:yì # 㚤 0x36a5:yú # 㚥 0x36a6:yí # 㚦 0x36a7:yǎn # 㚧 0x36a9:rǎn # 㚩 0x36aa:hào # 㚪 0x36ab:shà,zhà # 㚫 0x36ad:yóu # 㚭 0x36af:xín,xún # 㚯 0x36b0:bǐ # 㚰 0x36b2:diǎn,shàn,chān # 㚲 0x36b4:bù # 㚴 0x36b6:sì # 㚶 0x36b7:ěr,nǎi # 㚷 0x36b9:mǎo # 㚹 0x36ba:yùn # 㚺 0x36bd:qiǎo # 㚽 0x36bf:páo # 㚿 0x36c2:nuǒ # 㛂 0x36c3:jié # 㛃 0x36c5:èr # 㛅 0x36c6:duǒ,duò # 㛆 0x36ca:duǒ # 㛊 0x36cd:qiè # 㛍 0x36cf:òu,qiú # 㛏 0x36d0:sǎo # 㛐 0x36d1:càn # 㛑 0x36d2:dòu # 㛒 0x36d4:péng # 㛔 0x36d5:yì # 㛕 0x36d7:zuò,qiē # 㛗 0x36d8:pò # 㛘 0x36d9:qiè,qín,shěn,shèn # 㛙 0x36da:tǒng # 㛚 0x36db:xìn,zhèn # 㛛 0x36dc:yóu # 㛜 0x36dd:bèi,bèng # 㛝 0x36de:lòng # 㛞 0x36e5:tà # 㛥 0x36e6:lǎn # 㛦 0x36e7:mǎn # 㛧 0x36e8:qiǎng # 㛨 0x36e9:zhóu # 㛩 0x36ea:yàn,yuán # 㛪 0x36ec:lù # 㛬 0x36ee:sǎo # 㛮 0x36ef:miǎn # 㛯 0x36f1:ruì,wěi # 㛱 0x36f2:fà # 㛲 0x36f3:chà,yì # 㛳 0x36f4:nǎo # 㛴 0x36f6:chóu,tán,tàn # 㛶 0x36f8:shù # 㛸 0x36f9:pián # 㛹 0x36fb:kuǐ # 㛻 0x36fc:shà,chā # 㛼 0x36fe:xián # 㛾 0x36ff:zhì # 㛿 0x3703:liàn,liáo,máng # 㜃 0x3704:xún # 㜄 0x3705:xù # 㜅 0x3706:mì # 㜆 0x3707:huì,yè # 㜇 0x3708:mù # 㜈 0x370a:pàng,zhǎn # 㜊 0x370b:yì # 㜋 0x370c:gòu # 㜌 0x370d:táng # 㜍 0x370e:xī,xì # 㜎 0x370f:yún # 㜏 0x3710:shù # 㜐 0x3711:fú,pó # 㜑 0x3712:yì # 㜒 0x3713:dá # 㜓 0x3715:lián # 㜕 0x3716:cáo # 㜖 0x3717:cǎn,chú,xuàn # 㜗 0x3718:jù # 㜘 0x3719:lù # 㜙 0x371a:sù # 㜚 0x371b:nèn,ruǎn # 㜛 0x371c:ào # 㜜 0x371d:ǎn,àn # 㜝 0x371e:qiàn # 㜞 0x3723:rán,niàn # 㜣 0x3724:shěn,niǎn # 㜤 0x3725:mái,mó # 㜥 0x3726:hàn,niè,sì,xié,xín # 㜦 0x3727:yuè # 㜧 0x3728:ér,nái # 㜨 0x3729:ào # 㜩 0x372a:xiǎn # 㜪 0x372b:mà,méi,měi # 㜫 0x372e:làn # 㜮 0x3730:yuè # 㜰 0x3731:dòng,zhì # 㜱 0x3732:wěng,yíng # 㜲 0x3733:huái # 㜳 0x3734:mèng # 㜴 0x3735:niǎo # 㜵 0x3736:fàn # 㜶 0x3737:mí,nǎi,xiǎn # 㜷 0x3738:niè # 㜸 0x3739:qú # 㜹 0x373a:zàn # 㜺 0x373b:liàn # 㜻 0x373c:zhí,zhì # 㜼 0x373d:zǐ # 㜽 0x373e:hái # 㜾 0x373f:xù # 㜿 0x3740:hào # 㝀 0x3741:xún # 㝁 0x3742:zhì # 㝂 0x3743:fàn,miǎn,wǎn # 㝃 0x3744:chún,qì,rùn # 㝄 0x3745:gòu # 㝅 0x3747:chún # 㝇 0x3748:luán # 㝈 0x3749:zhù # 㝉 0x374a:shǒu # 㝊 0x374b:liáo,liǎo,liú # 㝋 0x374c:jié,jiù,zhòu # 㝌 0x374d:xiě # 㝍 0x374e:dìng # 㝎 0x374f:jiè # 㝏 0x3750:róng # 㝐 0x3751:máng,páng # 㝑 0x3753:gé,kè # 㝓 0x3754:yào # 㝔 0x3755:níng # 㝕 0x3756:yí,yín # 㝖 0x3757:láng # 㝗 0x3758:yóng # 㝘 0x3759:yín # 㝙 0x375b:sù # 㝛 0x375d:lín # 㝝 0x375e:yā # 㝞 0x375f:máo,mào,kuān # 㝟 0x3760:míng # 㝠 0x3761:zuì # 㝡 0x3762:yǔ # 㝢 0x3763:yè,yì # 㝣 0x3764:gòu # 㝤 0x3765:mǐ # 㝥 0x3766:jùn,yá # 㝦 0x3767:wěn # 㝧 0x376a:diàn,dǐng # 㝪 0x376b:lóng # 㝫 0x376d:xǐng # 㝭 0x376e:cuì # 㝮 0x376f:qiáo # 㝯 0x3770:mián # 㝰 0x3771:mèng # 㝱 0x3772:qǐn # 㝲 0x3774:wán # 㝴 0x3775:dé # 㝵 0x3776:ài,dé # 㝶 0x3778:biàn # 㝸 0x3779:nóu # 㝹 0x377a:lián,lín # 㝺 0x377b:jǐn # 㝻 0x377d:chuí,shuǐ,zhuǐ # 㝽 0x377e:zuǒ # 㝾 0x377f:bó,bǒ,fù,qiàn # 㝿 0x3781:yào # 㞁 0x3782:tuǐ # 㞂 0x3783:jí # 㞃 0x3785:guǒ # 㞅 0x3786:jǐ # 㞆 0x3787:wěi # 㞇 0x378a:xù # 㞊 0x378b:niǎn # 㞋 0x378c:yùn # 㞌 0x378e:bǎ,fú,pá # 㞎 0x378f:zhé # 㞏 0x3790:jū # 㞐 0x3791:wěi # 㞑 0x3792:xì,xiè # 㞒 0x3793:qǐ,qì # 㞓 0x3794:yí # 㞔 0x3795:xiè # 㞕 0x3796:cì # 㞖 0x3797:qiú # 㞗 0x3798:tún # 㞘 0x3799:niào # 㞙 0x379a:qì,zhǎ # 㞚 0x379b:jǐ # 㞛 0x379f:diàn # 㞟 0x37a0:láo,liáo # 㞠 0x37a1:zhǎn # 㞡 0x37a4:yín # 㞤 0x37a5:cén # 㞥 0x37a6:jǐ # 㞦 0x37a7:huì # 㞧 0x37a8:zǎi,zǐ # 㞨 0x37a9:lán # 㞩 0x37aa:náo # 㞪 0x37ab:jù,zǒu # 㞫 0x37ac:qìn # 㞬 0x37ad:dài # 㞭 0x37af:jié # 㞯 0x37b0:xǔ # 㞰 0x37b2:yòng # 㞲 0x37b3:dǒu # 㞳 0x37b4:chí # 㞴 0x37b6:mǐn # 㞶 0x37b7:huáng # 㞷 0x37b8:suì # 㞸 0x37b9:kě # 㞹 0x37ba:zú # 㞺 0x37bb:hào # 㞻 0x37bc:chéng,shèng,zhé # 㞼 0x37bd:xuè # 㞽 0x37be:ní,yì # 㞾 0x37bf:chì,qí # 㞿 0x37c0:lián # 㟀 0x37c1:àn # 㟁 0x37c2:chǐ,mǔ # 㟂 0x37c4:xiáng # 㟄 0x37c5:yáng # 㟅 0x37c6:huá # 㟆 0x37c7:cuó,cuǒ # 㟇 0x37c8:qiú # 㟈 0x37c9:láo # 㟉 0x37ca:fú # 㟊 0x37cb:duì # 㟋 0x37cc:máng # 㟌 0x37cd:láng # 㟍 0x37ce:tuǒ # 㟎 0x37cf:hán # 㟏 0x37d0:mǎng # 㟐 0x37d1:bó # 㟑 0x37d3:qí # 㟓 0x37d4:hán # 㟔 0x37d6:lòng # 㟖 0x37d8:tiáo # 㟘 0x37d9:lǎo,zé,zhái # 㟙 0x37da:qí # 㟚 0x37db:zàn # 㟛 0x37dc:mí # 㟜 0x37dd:péi,pǒu # 㟝 0x37de:zhàn # 㟞 0x37df:xiàng # 㟟 0x37e0:gǎng # 㟠 0x37e2:qí # 㟢 0x37e4:lù # 㟤 0x37e6:yùn # 㟦 0x37e7:è,niè,xùn # 㟧 0x37e8:quán # 㟨 0x37e9:mín,mǐn,wěn # 㟩 0x37ea:wěi # 㟪 0x37eb:quán # 㟫 0x37ec:shǔ,sǒu # 㟬 0x37ed:mín # 㟭 0x37f0:mǐng # 㟰 0x37f1:yǎo # 㟱 0x37f2:jué,yuán # 㟲 0x37f3:lì # 㟳 0x37f4:kuài,kuǐ,wěi # 㟴 0x37f5:gǎng # 㟵 0x37f6:yuán # 㟶 0x37f7:da # 㟷 0x37f9:láo # 㟹 0x37fa:lóu # 㟺 0x37fb:qiàn # 㟻 0x37fc:áo # 㟼 0x37fd:biǎo # 㟽 0x37ff:máng,mǎng # 㟿 0x3800:dǎo # 㠀 0x3802:áo # 㠂 0x3804:xí # 㠄 0x3805:fú,fù # 㠅 0x3807:jiù # 㠇 0x3808:rùn # 㠈 0x3809:tóng # 㠉 0x380a:qū # 㠊 0x380b:è # 㠋 0x380d:jí,jié,qì # 㠍 0x380e:qì # 㠎 0x380f:huá # 㠏 0x3810:jiào # 㠐 0x3811:zuì # 㠑 0x3812:biǎo # 㠒 0x3813:méng # 㠓 0x3814:bài # 㠔 0x3815:wěi # 㠕 0x3816:jì,yǐ # 㠖 0x3817:ào,wò # 㠗 0x3818:yǔ # 㠘 0x3819:háo # 㠙 0x381a:duì,zhuó # 㠚 0x381b:wò # 㠛 0x381c:nì # 㠜 0x381d:cuán # 㠝 0x381f:lí # 㠟 0x3820:lú # 㠠 0x3821:niǎo # 㠡 0x3822:huái # 㠢 0x3823:lài,lì # 㠣 0x3825:lǜ # 㠥 0x3827:mí,mǐ # 㠧 0x3828:yù # 㠨 0x382a:jù # 㠪 0x382d:zhǎn,zhàn # 㠭 0x382f:yǐ # 㠯 0x3831:jì,qǐ # 㠱 0x3832:bǐ # 㠲 0x3834:rèn # 㠴 0x3836:fán # 㠶 0x3837:gé # 㠷 0x3838:kù # 㠸 0x3839:jiè # 㠹 0x383a:miáo # 㠺 0x383d:tóng # 㠽 0x383f:cǐ # 㠿 0x3840:bì # 㡀 0x3841:kǎi,kuà # 㡁 0x3842:lì # 㡂 0x3844:sǔn,xún # 㡄 0x3845:nuǒ # 㡅 0x3847:jí,zhé # 㡇 0x3848:mén,wèn # 㡈 0x3849:xián,yán # 㡉 0x384a:qià,qiǎn # 㡊 0x384b:è,yé # 㡋 0x384c:mào,mèi # 㡌 0x384f:tóu,shū # 㡏 0x3851:qiǎo # 㡑 0x3854:wù,mù # 㡔 0x3856:chuáng # 㡖 0x3857:tí # 㡗 0x3858:lián # 㡘 0x3859:bī,pí # 㡙 0x385b:máng # 㡛 0x385c:xuě # 㡜 0x385d:fèng,fú # 㡝 0x385e:lěi,lóu # 㡞 0x3860:zhèng # 㡠 0x3861:chú # 㡡 0x3862:màn # 㡢 0x3863:lóng # 㡣 0x3865:yǐn # 㡥 0x3867:zhèng # 㡧 0x3868:qiān,jiān # 㡨 0x3869:luán # 㡩 0x386a:nié # 㡪 0x386b:yì # 㡫 0x386d:jì # 㡭 0x386e:jí # 㡮 0x386f:zhái,dù # 㡯 0x3870:yǔ # 㡰 0x3871:jiǔ # 㡱 0x3872:huán # 㡲 0x3873:dǐ,zhé,zhǐ # 㡳 0x3875:líng # 㡵 0x3876:zhǐ # 㡶 0x3877:běn # 㡷 0x3878:zhǎ,zhà # 㡸 0x3879:cì,jū # 㡹 0x387a:dàn # 㡺 0x387b:liào # 㡻 0x387c:yì # 㡼 0x387d:zhào # 㡽 0x387e:xiàn # 㡾 0x387f:chì # 㡿 0x3880:cì,zì # 㢀 0x3881:chǐ # 㢁 0x3882:yǎn # 㢂 0x3883:láng # 㢃 0x3884:dòu # 㢄 0x3885:lòng # 㢅 0x3886:chán # 㢆 0x3888:tuí # 㢈 0x3889:chá # 㢉 0x388a:ǎi # 㢊 0x388b:chǐ # 㢋 0x388d:yíng,yǐng # 㢍 0x388e:chà,zé,zhái,zhé # 㢎 0x388f:tóu # 㢏 0x3891:tuí # 㢑 0x3892:chá # 㢒 0x3893:yǎo,zhàng # 㢓 0x3894:zǒng # 㢔 0x3897:qiào # 㢗 0x3898:lián # 㢘 0x3899:qín # 㢙 0x389a:lǔ # 㢚 0x389b:yàn # 㢛 0x389e:yì # 㢞 0x389f:chǎn,chān # 㢟 0x38a0:jiǒng,jùn # 㢠 0x38a1:jiǎng # 㢡 0x38a3:jìng,qíng # 㢣 0x38a5:dòng # 㢥 0x38a7:juàn # 㢧 0x38a8:hàn # 㢨 0x38a9:dì # 㢩 0x38ac:hóng # 㢬 0x38ae:chí # 㢮 0x38af:mín # 㢯 0x38b0:bì,huán # 㢰 0x38b2:xùn # 㢲 0x38b3:lú # 㢳 0x38b5:shè,xié # 㢵 0x38b6:bì # 㢶 0x38b8:bì # 㢸 0x38ba:xián # 㢺 0x38bb:wěi # 㢻 0x38bc:biè # 㢼 0x38bd:ěr # 㢽 0x38be:juàn # 㢾 0x38c0:zhèn # 㣀 0x38c1:bèi # 㣁 0x38c2:yì # 㣂 0x38c3:yǔ,yù # 㣃 0x38c4:qú # 㣄 0x38c5:zàn # 㣅 0x38c6:mí,mí,pèi # 㣆 0x38c7:nǐ,yì # 㣇 0x38c8:sì # 㣈 0x38cc:shàn # 㣌 0x38cd:tái # 㣍 0x38ce:mù # 㣎 0x38cf:jìng # 㣏 0x38d0:biàn # 㣐 0x38d1:róng # 㣑 0x38d2:cèng # 㣒 0x38d3:càn # 㣓 0x38d9:dí # 㣙 0x38da:tóng,tǒng # 㣚 0x38db:tà # 㣛 0x38dc:xíng # 㣜 0x38de:duó,duò # 㣞 0x38df:xì # 㣟 0x38e0:tóng # 㣠 0x38e2:tí # 㣢 0x38e3:shǎn,shàn # 㣣 0x38e4:jiàn # 㣤 0x38e5:zhì # 㣥 0x38e7:yìn,yǒng # 㣧 0x38ea:huǎn,kuò # 㣪 0x38eb:zhǒng # 㣫 0x38ec:qì # 㣬 0x38ef:xiè # 㣯 0x38f0:xiè # 㣰 0x38f1:zé,zuò # 㣱 0x38f2:wéi # 㣲 0x38f5:tà # 㣵 0x38f6:zhān # 㣶 0x38f7:nìng # 㣷 0x38fb:yì # 㣻 0x38fc:rěn # 㣼 0x38fd:shù # 㣽 0x38fe:chà # 㣾 0x38ff:zhuó # 㣿 0x3901:miǎn,tiǎn # 㤁 0x3902:jí # 㤂 0x3903:fáng # 㤃 0x3904:pèi # 㤄 0x3905:ài # 㤅 0x3906:fàn # 㤆 0x3907:ǎo,fó,wù # 㤇 0x3908:qìn # 㤈 0x3909:qiā,yá # 㤉 0x390a:xiào,yáo # 㤊 0x390d:qiǎo # 㤍 0x390f:tóng # 㤏 0x3911:yōu # 㤑 0x3913:bèn # 㤓 0x3914:fú,fù # 㤔 0x3915:chù # 㤕 0x3916:zhù # 㤖 0x3918:chù,cù,zhòu # 㤘 0x391a:háng # 㤚 0x391b:nín,rèn # 㤛 0x391c:jué,yù # 㤜 0x391e:chà # 㤞 0x391f:kǒng,tòu # 㤟 0x3920:liè # 㤠 0x3921:lì # 㤡 0x3922:xù,yù # 㤢 0x3924:yú,yǔ # 㤤 0x3925:hài # 㤥 0x3926:lì # 㤦 0x3927:hóu,hòu # 㤧 0x3928:gǒng,qióng # 㤨 0x3929:kè # 㤩 0x392a:yuàn # 㤪 0x392b:dé # 㤫 0x392c:huì,kuì # 㤬 0x392e:kuáng,guàng # 㤮 0x392f:jiǒng,jùn # 㤯 0x3930:zǎn,zuò # 㤰 0x3931:fù # 㤱 0x3932:qiè,qù # 㤲 0x3933:běi # 㤳 0x3934:xí # 㤴 0x3935:cí # 㤵 0x3936:páng # 㤶 0x3938:xì # 㤸 0x3939:qiú # 㤹 0x393a:huǎng # 㤺 0x393d:chóu # 㤽 0x393e:sàn # 㤾 0x3940:dé # 㥀 0x3941:dé,zhí,zhòu # 㥁 0x3942:tè # 㥂 0x3943:mèn # 㥃 0x3944:líng # 㥄 0x3945:shòu # 㥅 0x3946:diàn,tuì # 㥆 0x3947:cán,càn # 㥇 0x3948:dié # 㥈 0x3949:chè,chì # 㥉 0x394a:péng # 㥊 0x394c:jú # 㥌 0x394d:jì # 㥍 0x394e:lái,lí # 㥎 0x394f:tiǎn # 㥏 0x3950:yuàn # 㥐 0x3952:cǎi # 㥒 0x3953:qǐ # 㥓 0x3954:yú,yù # 㥔 0x3955:lián # 㥕 0x395a:yú # 㥚 0x395b:jí,kè,sù # 㥛 0x395c:wèi # 㥜 0x395d:mǐ,miǎn # 㥝 0x395e:cuì,qiàn,suì # 㥞 0x395f:xié # 㥟 0x3960:xǔ # 㥠 0x3961:xì # 㥡 0x3962:qiú # 㥢 0x3963:huì # 㥣 0x3965:yú # 㥥 0x3966:qiè,xiá,xiǎn # 㥦 0x3967:shùn # 㥧 0x3968:chuí,shuì,wěi # 㥨 0x3969:duǒ # 㥩 0x396a:lóu # 㥪 0x396c:páng # 㥬 0x396d:tài # 㥭 0x396e:zhòu # 㥮 0x396f:yǐn # 㥯 0x3971:fěi # 㥱 0x3972:shèn,yín # 㥲 0x3973:yuán # 㥳 0x3974:yí,yǐ # 㥴 0x3975:hùn # 㥵 0x3976:sè # 㥶 0x3977:yè,yì # 㥷 0x3978:mǐn # 㥸 0x3979:fěn # 㥹 0x397a:hé,hè # 㥺 0x397c:yǐn # 㥼 0x397d:cè,zé # 㥽 0x397e:nì # 㥾 0x397f:ào # 㥿 0x3980:féng # 㦀 0x3981:lián # 㦁 0x3982:cháng,tàng # 㦂 0x3983:chǎn # 㦃 0x3984:má,mì # 㦄 0x3985:diē,dì # 㦅 0x3987:lù # 㦇 0x3989:yì # 㦉 0x398a:huá # 㦊 0x398c:tuì,xù,hū # 㦌 0x398d:è # 㦍 0x398e:huà # 㦎 0x398f:sǔn,xuàn # 㦏 0x3990:nì # 㦐 0x3991:liǎn,xiàn # 㦑 0x3992:lí # 㦒 0x3993:xiàn # 㦓 0x3994:yàn # 㦔 0x3995:lóng # 㦕 0x3996:mèn # 㦖 0x3997:jiàn,jìn # 㦗 0x399a:biǎn # 㦚 0x399b:yú,yǔ # 㦛 0x399c:huò,xuè # 㦜 0x399d:miǎo # 㦝 0x399e:chóu # 㦞 0x399f:hài,mái # 㦟 0x39a1:lè # 㦡 0x39a2:jié,qì # 㦢 0x39a3:wèi # 㦣 0x39a4:yì # 㦤 0x39a5:huán,xiǎn # 㦥 0x39a6:hè # 㦦 0x39a7:cǎn # 㦧 0x39a8:lán,làn # 㦨 0x39a9:yǐn # 㦩 0x39aa:xiè # 㦪 0x39ac:luǒ # 㦬 0x39ad:líng # 㦭 0x39ae:qián # 㦮 0x39af:huò # 㦯 0x39b1:wǒ # 㦱 0x39b4:gé,qià # 㦴 0x39b6:dié # 㦶 0x39b7:yǒng # 㦷 0x39b8:jǐ # 㦸 0x39b9:àng,yáng,yǐng # 㦹 0x39ba:rǔ,rù # 㦺 0x39bb:xí,zhé # 㦻 0x39bc:shuàng # 㦼 0x39bd:xù,yù # 㦽 0x39be:yí # 㦾 0x39bf:hù # 㦿 0x39c0:jí # 㧀 0x39c1:qù # 㧁 0x39c2:tián # 㧂 0x39c4:qiǎn,qiú # 㧄 0x39c5:mù,dāo # 㧅 0x39c7:mǎo # 㧇 0x39c8:yǐn,yìn # 㧈 0x39c9:gài,kuì # 㧉 0x39ca:bá,pō # 㧊 0x39cb:xiǎn,xuǎn # 㧋 0x39cc:mào # 㧌 0x39cd:fǎng # 㧍 0x39ce:yá,yà,qiā # 㧎 0x39d0:sǒng # 㧐 0x39d1:wéi,wěi # 㧑 0x39d2:xué,yù,yuè # 㧒 0x39d4:guài # 㧔 0x39d5:jiù,liǔ,yú # 㧕 0x39d6:è # 㧖 0x39d7:zǐ,jǐ,zhǐ # 㧗 0x39d8:cuì,nǎo,zì # 㧘 0x39d9:bì # 㧙 0x39da:wǎ # 㧚 0x39dc:liè # 㧜 0x39df:kuǎi # 㧟 0x39e1:hài # 㧡 0x39e3:zhù # 㧣 0x39e4:chòng # 㧤 0x39e5:xiǎn # 㧥 0x39e6:xuàn # 㧦 0x39e8:qiú # 㧨 0x39e9:pèi # 㧩 0x39ea:guǐ # 㧪 0x39eb:ér # 㧫 0x39ec:gǒng # 㧬 0x39ed:qióng # 㧭 0x39ef:lǎo # 㧯 0x39f0:lì # 㧰 0x39f1:chèn,ná,nì,nì,tiàn # 㧱 0x39f2:sǎn # 㧲 0x39f3:bǎi,bó,zhuò # 㧳 0x39f4:wǒ # 㧴 0x39f5:póu,pǒu # 㧵 0x39f7:duò,tùn # 㧷 0x39f9:tè # 㧹 0x39fa:tà # 㧺 0x39fb:zhǐ,zhuó,zú # 㧻 0x39fc:biào # 㧼 0x39fd:gù,hú # 㧽 0x3a00:bǐng # 㨀 0x3a01:zhí,zhì # 㨁 0x3a02:dǒng # 㨂 0x3a03:chéng,duǐ # 㨃 0x3a04:zhào # 㨄 0x3a05:nèi,ruì # 㨅 0x3a06:lǐn # 㨆 0x3a07:pó # 㨇 0x3a08:jǐ # 㨈 0x3a09:mǐn # 㨉 0x3a0a:wěi # 㨊 0x3a0b:chě,lè,zhèn # 㨋 0x3a0c:gòu,rú,rǔ # 㨌 0x3a0e:rú,ruán # 㨎 0x3a10:bǔ,péi # 㨐 0x3a12:kuí,wěi,xié # 㨒 0x3a13:láo,liáo # 㨓 0x3a14:hàn # 㨔 0x3a15:yíng # 㨕 0x3a16:zhì # 㨖 0x3a17:jié # 㨗 0x3a18:xǐng # 㨘 0x3a19:xié # 㨙 0x3a1a:xún # 㨚 0x3a1b:shǎn # 㨛 0x3a1c:qián # 㨜 0x3a1d:xiè # 㨝 0x3a1e:sù # 㨞 0x3a1f:hái # 㨟 0x3a20:mì # 㨠 0x3a21:hún # 㨡 0x3a24:huì,kuǎi,wài # 㨤 0x3a25:nà # 㨥 0x3a26:sǒng # 㨦 0x3a27:bèn # 㨧 0x3a28:liù # 㨨 0x3a29:jié # 㨩 0x3a2a:huàng # 㨪 0x3a2b:lǎn # 㨫 0x3a2d:hù # 㨭 0x3a2e:dōu # 㨮 0x3a2f:huò,kuò # 㨯 0x3a30:gé,gǔn,hùn,huò,jié # 㨰 0x3a31:yáo # 㨱 0x3a32:cè # 㨲 0x3a33:guǐ # 㨳 0x3a34:jiàn # 㨴 0x3a35:jiǎn # 㨵 0x3a36:chóu,dǎo,zhǒu,zhòu # 㨶 0x3a37:jìn # 㨷 0x3a38:mà # 㨸 0x3a39:huì # 㨹 0x3a3a:mén,mì,miǎn # 㨺 0x3a3b:cán,shǎn,zàn # 㨻 0x3a3c:lüè # 㨼 0x3a3d:pǐ,pì,qiǎo # 㨽 0x3a3e:yàng # 㨾 0x3a3f:jù # 㨿 0x3a40:jù # 㩀 0x3a41:què # 㩁 0x3a44:shāi # 㩄 0x3a46:jiù # 㩆 0x3a47:huà,huò # 㩇 0x3a48:xiàn,yǔn # 㩈 0x3a49:xié # 㩉 0x3a4b:sù,xiāo # 㩋 0x3a4c:fèi # 㩌 0x3a4d:cè # 㩍 0x3a4e:yè # 㩎 0x3a52:qín # 㩒 0x3a53:huǐ # 㩓 0x3a54:tún # 㩔 0x3a56:qiáng,tiáo # 㩖 0x3a57:xí,xié # 㩗 0x3a58:yǐ # 㩘 0x3a5a:méng # 㩚 0x3a5b:tuán # 㩛 0x3a5c:lǎn # 㩜 0x3a5d:háo # 㩝 0x3a5e:cì # 㩞 0x3a5f:zhài # 㩟 0x3a60:piǎo # 㩠 0x3a61:luǒ # 㩡 0x3a62:mí,miè # 㩢 0x3a66:xié # 㩦 0x3a67:bó # 㩧 0x3a68:huì # 㩨 0x3a69:qǐ,qǐng # 㩩 0x3a6a:xié,xìn,yé # 㩪 0x3a6d:bó,jiǎo,xiào # 㩭 0x3a6e:qián,xián # 㩮 0x3a6f:bǎn,pán,pó # 㩯 0x3a70:jiǎo,qiáo,xiǔ # 㩰 0x3a71:jué # 㩱 0x3a72:kǔn,quán # 㩲 0x3a73:sǒng # 㩳 0x3a74:jú # 㩴 0x3a75:è # 㩵 0x3a76:niè,nǐng # 㩶 0x3a78:dié # 㩸 0x3a79:dié,zhá # 㩹 0x3a7b:guǐ,qī # 㩻 0x3a7d:qí # 㩽 0x3a7e:chuí # 㩾 0x3a80:yú # 㪀 0x3a81:qín # 㪁 0x3a83:hé # 㪃 0x3a84:fú # 㪄 0x3a86:dǐ # 㪆 0x3a87:xiàn # 㪇 0x3a88:guì # 㪈 0x3a89:hé # 㪉 0x3a8a:qún # 㪊 0x3a8b:hàn # 㪋 0x3a8c:tǒng,yú,yǔ # 㪌 0x3a8d:bó # 㪍 0x3a8e:shǎn # 㪎 0x3a8f:bǐ # 㪏 0x3a90:lù # 㪐 0x3a91:yè # 㪑 0x3a92:ní # 㪒 0x3a93:chuái # 㪓 0x3a94:sàn,tán # 㪔 0x3a95:diào # 㪕 0x3a96:lù # 㪖 0x3a97:tǒu # 㪗 0x3a98:liǎn # 㪘 0x3a99:kě,kè,kuò # 㪙 0x3a9a:sàn # 㪚 0x3a9b:zhěn # 㪛 0x3a9c:chuǎi # 㪜 0x3a9d:liàn # 㪝 0x3a9e:mào # 㪞 0x3aa0:qiàn # 㪠 0x3aa1:kě # 㪡 0x3aa2:shǎo # 㪢 0x3aa3:qiào # 㪣 0x3aa4:bì # 㪤 0x3aa6:yìn # 㪦 0x3aa8:shàn # 㪨 0x3aa9:sù # 㪩 0x3aaa:sà,xǐ # 㪪 0x3aab:ruì # 㪫 0x3aac:zhuó # 㪬 0x3aad:lú # 㪭 0x3aae:líng # 㪮 0x3aaf:chá,jǔ,qú # 㪯 0x3ab1:huàn # 㪱 0x3ab4:jiá # 㪴 0x3ab5:bàn # 㪵 0x3ab6:hú # 㪶 0x3ab7:dǒu # 㪷 0x3ab9:lǒu # 㪹 0x3abb:juàn # 㪻 0x3abc:kě # 㪼 0x3abd:suǒ,suò # 㪽 0x3abe:gé,luò # 㪾 0x3abf:zhé,shé # 㪿 0x3ac0:dǐng # 㫀 0x3ac1:duàn # 㫁 0x3ac2:zhù # 㫂 0x3ac3:yǎn # 㫃 0x3ac4:páng # 㫄 0x3ac5:chá,qí,shí # 㫅 0x3aca:yǐ # 㫊 0x3acd:yóu # 㫍 0x3ace:gǔn,kuài # 㫎 0x3acf:yǎo # 㫏 0x3ad0:yǎo # 㫐 0x3ad1:shí,zhǐ # 㫑 0x3ad2:gǒng # 㫒 0x3ad3:qǐ,qì # 㫓 0x3ad4:gèn # 㫔 0x3ad7:hòu # 㫗 0x3ad8:mì,miǎn # 㫘 0x3ad9:fú # 㫙 0x3ada:hū # 㫚 0x3adb:guàng,kuáng,kuàng,mǔ # 㫛 0x3adc:dàn,tǎn # 㫜 0x3adf:yán # 㫟 0x3ae2:qù # 㫢 0x3ae4:chǎng,zhào # 㫤 0x3ae5:mǐng # 㫥 0x3ae7:bào # 㫧 0x3aeb:xiǎn # 㫫 0x3aef:mào # 㫯 0x3af0:lǎng # 㫰 0x3af1:nǎn # 㫱 0x3af2:pèi # 㫲 0x3af3:chén # 㫳 0x3af6:cǒu,zhǒu # 㫶 0x3af8:qiè # 㫸 0x3af9:dài,shù,yú # 㫹 0x3afb:kùn # 㫻 0x3afc:dié,zhé,zhì # 㫼 0x3afd:lù # 㫽 0x3b02:yú # 㬂 0x3b03:tái # 㬃 0x3b04:chàn # 㬄 0x3b05:màn # 㬅 0x3b06:mián,miàn,mǐn # 㬆 0x3b07:huàn # 㬇 0x3b09:nuǎn,ruò # 㬉 0x3b0a:huǎn # 㬊 0x3b0b:hóu # 㬋 0x3b0c:jìng # 㬌 0x3b0d:bó # 㬍 0x3b0e:xiǎn # 㬎 0x3b0f:lì # 㬏 0x3b10:jǐn,jìn,xíng,yǐng # 㬐 0x3b12:mǎng,mào # 㬒 0x3b13:piào # 㬓 0x3b14:háo # 㬔 0x3b15:yáng # 㬕 0x3b17:xiàn # 㬗 0x3b18:sù # 㬘 0x3b19:wěi # 㬙 0x3b1a:chè # 㬚 0x3b1c:jìn # 㬜 0x3b1d:céng # 㬝 0x3b1e:hè # 㬞 0x3b20:shài # 㬠 0x3b21:líng # 㬡 0x3b23:duì # 㬣 0x3b25:pù # 㬥 0x3b26:yuè # 㬦 0x3b27:bó # 㬧 0x3b29:huì # 㬩 0x3b2a:dié,zhì # 㬪 0x3b2b:yàn # 㬫 0x3b2c:jù # 㬬 0x3b2d:jiào,shǎn,yǎo # 㬭 0x3b2e:kuài,nàn # 㬮 0x3b2f:liè # 㬯 0x3b30:yú # 㬰 0x3b31:tì # 㬱 0x3b33:wǔ # 㬳 0x3b34:hǒng # 㬴 0x3b35:xiáo,jiāo # 㬵 0x3b36:hào # 㬶 0x3b3b:huǎng # 㬻 0x3b3c:fù # 㬼 0x3b3f:dùn # 㬿 0x3b41:réng # 㭁 0x3b42:jiǎo # 㭂 0x3b44:xìn # 㭄 0x3b47:yuàn # 㭇 0x3b48:jué,kuài # 㭈 0x3b49:huá # 㭉 0x3b4b:bàng # 㭋 0x3b4c:móu,yú # 㭌 0x3b4f:wěi # 㭏 0x3b51:mèi # 㭑 0x3b52:sì # 㭒 0x3b53:biàn # 㭓 0x3b54:lú # 㭔 0x3b58:hé,gé # 㭘 0x3b59:shé,zhé # 㭙 0x3b5a:lǚ # 㭚 0x3b5b:pài # 㭛 0x3b5c:róng # 㭜 0x3b5d:qiú # 㭝 0x3b5e:liè # 㭞 0x3b5f:gǒng # 㭟 0x3b60:xiǎn # 㭠 0x3b61:xì,xìn # 㭡 0x3b64:niǎo # 㭤 0x3b68:yé # 㭨 0x3b69:lèi,líng,liè # 㭩 0x3b6b:cuán,cuó,zhèn # 㭫 0x3b6c:zhuó # 㭬 0x3b6d:fèi # 㭭 0x3b6e:zuò # 㭮 0x3b6f:dié,nà,zhé # 㭯 0x3b70:jì,jué,zuǐ # 㭰 0x3b71:hé,xiá # 㭱 0x3b72:jí # 㭲 0x3b78:tú # 㭸 0x3b79:xián # 㭹 0x3b7a:yǎn # 㭺 0x3b7b:táng # 㭻 0x3b7c:tà # 㭼 0x3b7d:dǐ # 㭽 0x3b7e:jué,yuè # 㭾 0x3b7f:áng # 㭿 0x3b80:hán # 㮀 0x3b81:yáo # 㮁 0x3b82:jú # 㮂 0x3b83:ruí # 㮃 0x3b84:bǎng,bì,péng # 㮄 0x3b86:niè # 㮆 0x3b87:tiàn # 㮇 0x3b88:nài # 㮈 0x3b8b:yǒu,yù # 㮋 0x3b8c:mián,mǐn # 㮌 0x3b8f:nài # 㮏 0x3b90:xǐng,shěng # 㮐 0x3b91:qì # 㮑 0x3b93:gèn # 㮓 0x3b94:tóng # 㮔 0x3b95:ér,ruǎn # 㮕 0x3b96:jiá,jiá # 㮖 0x3b97:qín # 㮗 0x3b98:mào # 㮘 0x3b99:è # 㮙 0x3b9a:lì # 㮚 0x3b9b:chí # 㮛 0x3b9d:hé,luò # 㮝 0x3b9e:jié,ní,yá # 㮞 0x3b9f:jí,niǎn,pèng,ròu,kā # 㮟 0x3ba1:guàn # 㮡 0x3ba2:hóu # 㮢 0x3ba3:gài,zé # 㮣 0x3ba5:fèn # 㮥 0x3ba6:sè,suǒ # 㮦 0x3ba8:jí,jì # 㮨 0x3baa:qióng # 㮪 0x3bab:hé # 㮫 0x3bad:xián # 㮭 0x3bae:jié # 㮮 0x3baf:huá,hún,kuǎn # 㮯 0x3bb0:bí,pí # 㮰 0x3bb3:zhèn # 㮳 0x3bb6:shì,shuò # 㮶 0x3bb8:sòng # 㮸 0x3bb9:zhǐ # 㮹 0x3bba:běn # 㮺 0x3bbe:lǎng # 㮾 0x3bbf:bì # 㮿 0x3bc0:xiǎn,xuàn # 㯀 0x3bc1:bàng # 㯁 0x3bc2:dài # 㯂 0x3bc5:pí # 㯅 0x3bc6:chǎn # 㯆 0x3bc7:bì # 㯇 0x3bc8:sù # 㯈 0x3bc9:huò,chū # 㯉 0x3bca:hén # 㯊 0x3bcb:yǐng # 㯋 0x3bcc:chuán # 㯌 0x3bcd:jiǎng # 㯍 0x3bce:nèn # 㯎 0x3bcf:gǔ # 㯏 0x3bd0:fǎng,tuǒ # 㯐 0x3bd3:tà # 㯓 0x3bd4:cuì # 㯔 0x3bd6:dé # 㯖 0x3bd7:rǎn,shùn,xián,xiàn # 㯗 0x3bd8:kuǎn # 㯘 0x3bd9:chè # 㯙 0x3bda:dá # 㯚 0x3bdb:hú,huò # 㯛 0x3bdc:cuì # 㯜 0x3bdd:lù # 㯝 0x3bde:juàn,yuè # 㯞 0x3bdf:lù # 㯟 0x3be0:qiàn,xiàn,xún # 㯠 0x3be1:pào # 㯡 0x3be2:zhèn # 㯢 0x3be4:lì # 㯤 0x3be5:cáo,zāo # 㯥 0x3be6:qí # 㯦 0x3be9:tì # 㯩 0x3bea:líng # 㯪 0x3beb:qú # 㯫 0x3bec:liǎn # 㯬 0x3bed:lǔ # 㯭 0x3bee:shǔ # 㯮 0x3bef:gòng # 㯯 0x3bf0:zhé,zhí # 㯰 0x3bf1:biǎo,piáo,pāo # 㯱 0x3bf2:jìn # 㯲 0x3bf3:qíng # 㯳 0x3bf6:zōng # 㯶 0x3bf7:pú # 㯷 0x3bf8:jǐn # 㯸 0x3bf9:biǎo # 㯹 0x3bfa:jiàn # 㯺 0x3bfb:gǔn,hùn # 㯻 0x3bff:liè # 㯿 0x3c00:lí # 㰀 0x3c01:luǒ # 㰁 0x3c02:shěn,sǔn # 㰂 0x3c03:mián # 㰃 0x3c04:jiàn # 㰄 0x3c05:dí # 㰅 0x3c06:bèi # 㰆 0x3c08:liǎn # 㰈 0x3c0a:xún # 㰊 0x3c0b:pín # 㰋 0x3c0c:què # 㰌 0x3c0d:lóng # 㰍 0x3c0e:zuì # 㰎 0x3c10:jué,kuí,lěi,tuǐ,tuǒ # 㰐 0x3c12:shé,xué # 㰒 0x3c14:xiè # 㰔 0x3c16:lǎn # 㰖 0x3c17:cù # 㰗 0x3c18:yí # 㰘 0x3c19:nuó # 㰙 0x3c1a:lí # 㰚 0x3c1b:yuè # 㰛 0x3c1d:yǐ # 㰝 0x3c1f:jì,qì # 㰟 0x3c20:kàng # 㰠 0x3c21:xiè # 㰡 0x3c23:zì # 㰣 0x3c24:hē,qiè # 㰤 0x3c25:huì # 㰥 0x3c26:qù # 㰦 0x3c2a:wá # 㰪 0x3c2c:xún # 㰬 0x3c2e:shèn # 㰮 0x3c2f:tòu,tǒu,hòu # 㰯 0x3c30:qiè # 㰰 0x3c31:shà # 㰱 0x3c32:xù,yù # 㰲 0x3c33:yà # 㰳 0x3c34:pó,pǒu # 㰴 0x3c35:zú # 㰵 0x3c36:yǒu # 㰶 0x3c37:zì # 㰷 0x3c38:liǎn,liàn,luǎn # 㰸 0x3c39:jìn # 㰹 0x3c3a:xiá,xià # 㰺 0x3c3b:yǐ # 㰻 0x3c3c:qiè # 㰼 0x3c3d:mǐ,yàn # 㰽 0x3c3e:jiào # 㰾 0x3c40:chǐ,chuài # 㱀 0x3c41:shì # 㱁 0x3c43:yǐn # 㱃 0x3c44:mò # 㱄 0x3c45:yì # 㱅 0x3c47:sè,xì # 㱇 0x3c48:jìn # 㱈 0x3c49:yè # 㱉 0x3c4b:què # 㱋 0x3c4c:chè,yǎn,yé # 㱌 0x3c4d:luán # 㱍 0x3c4f:zhèng # 㱏 0x3c56:cuì # 㱖 0x3c58:àn,yǎn # 㱘 0x3c59:xiǔ # 㱙 0x3c5a:cán,hài,shàn # 㱚 0x3c5b:chuǎn # 㱛 0x3c5c:zhá # 㱜 0x3c5e:jí # 㱞 0x3c5f:bó,pí,pǐ # 㱟 0x3c62:láng # 㱢 0x3c63:tuǐ # 㱣 0x3c65:líng # 㱥 0x3c66:è,guì,jǐ,qī # 㱦 0x3c67:wò # 㱧 0x3c68:liàn # 㱨 0x3c69:dú # 㱩 0x3c6a:mèn,hūn # 㱪 0x3c6b:làn # 㱫 0x3c6c:wěi # 㱬 0x3c6d:duàn # 㱭 0x3c6e:kuài,kuì # 㱮 0x3c6f:ái # 㱯 0x3c70:zǎi # 㱰 0x3c71:huì,wù,xì # 㱱 0x3c72:yì # 㱲 0x3c73:mò # 㱳 0x3c74:zì # 㱴 0x3c75:bèn,fèn # 㱵 0x3c76:bèng,jiào,péng,qiǎo,rù # 㱶 0x3c78:bì,bié # 㱸 0x3c79:lì,suàn,xiàn # 㱹 0x3c7a:lú # 㱺 0x3c7b:luǒ,luò # 㱻 0x3c7d:dàn,qín,zhěn # 㱽 0x3c7f:què # 㱿 0x3c80:chén # 㲀 0x3c82:chéng # 㲂 0x3c83:jiù # 㲃 0x3c84:kòu,kū # 㲄 0x3c85:jì # 㲅 0x3c86:líng # 㲆 0x3c88:sháo # 㲈 0x3c89:què # 㲉 0x3c8a:ruì # 㲊 0x3c8b:chuò,zhuó,zú # 㲋 0x3c8c:nèng # 㲌 0x3c8e:lóu # 㲎 0x3c8f:bǎo,piǎo,pín,pìng # 㲏 0x3c92:bào # 㲒 0x3c93:róng # 㲓 0x3c95:lèi # 㲕 0x3c98:qú # 㲘 0x3c9b:zhǐ # 㲛 0x3c9c:tán,tǎn # 㲜 0x3c9d:rǒng # 㲝 0x3c9e:zú # 㲞 0x3c9f:yǐng # 㲟 0x3ca0:máo # 㲠 0x3ca1:nài,nì # 㲡 0x3ca2:biàn,bié # 㲢 0x3ca5:táng # 㲥 0x3ca6:hàn,hě # 㲦 0x3ca7:zào # 㲧 0x3ca8:róng # 㲨 0x3cab:pú # 㲫 0x3cad:tǎn # 㲭 0x3caf:rán # 㲯 0x3cb0:níng # 㲰 0x3cb1:liè # 㲱 0x3cb2:dié,yì # 㲲 0x3cb3:dié # 㲳 0x3cb4:zhòng,zhòu # 㲴 0x3cb6:lǜ # 㲶 0x3cb7:dàn # 㲷 0x3cb9:guǐ,qiú # 㲹 0x3cba:jí,kè,léi # 㲺 0x3cbb:nì # 㲻 0x3cbc:yì # 㲼 0x3cbd:niàn,rěn,xiàn # 㲽 0x3cbe:yǔ,yù # 㲾 0x3cbf:wǎng # 㲿 0x3cc0:guò,kǎi,xì # 㳀 0x3cc1:zè # 㳁 0x3cc2:yán # 㳂 0x3cc3:cuì # 㳃 0x3cc4:xián # 㳄 0x3cc5:jiǎo,liú # 㳅 0x3cc6:shǔ,tǒu # 㳆 0x3cc7:fù # 㳇 0x3cc8:pèi # 㳈 0x3ccd:bù # 㳍 0x3cce:biàn,fàn # 㳎 0x3ccf:chǐ,shì # 㳏 0x3cd0:sà,zhá,zhǎ # 㳐 0x3cd1:yì # 㳑 0x3cd2:fǎ # 㳒 0x3cd4:duì # 㳔 0x3cd5:lán # 㳕 0x3cd7:chài # 㳗 0x3cd9:xuàn # 㳙 0x3cda:yù # 㳚 0x3cdb:yú # 㳛 0x3ce0:tà # 㳠 0x3ce5:jù,lòng # 㳥 0x3ce6:xiè # 㳦 0x3ce7:xí # 㳧 0x3ce8:jiǎn,zá,zǎn # 㳨 0x3cea:pàn,pì # 㳪 0x3ceb:tà # 㳫 0x3cec:xuán # 㳬 0x3ced:xián # 㳭 0x3cee:niào # 㳮 0x3cf4:mì # 㳴 0x3cf5:jì # 㳵 0x3cf6:gòu,nǒu # 㳶 0x3cf7:wěn,hū # 㳷 0x3cf9:wǎng # 㳹 0x3cfa:yóu # 㳺 0x3cfb:zé # 㳻 0x3cfc:bì # 㳼 0x3cfd:mǐ # 㳽 0x3cff:xiè # 㳿 0x3d00:fàn # 㴀 0x3d01:yì # 㴁 0x3d03:lèi,lì # 㴃 0x3d04:yíng # 㴄 0x3d06:jìn,xìng # 㴆 0x3d07:shè # 㴇 0x3d08:yìn # 㴈 0x3d09:jǐ # 㴉 0x3d0b:sù # 㴋 0x3d0f:wǎng # 㴏 0x3d10:miàn # 㴐 0x3d11:sù # 㴑 0x3d12:yì # 㴒 0x3d13:zǎi # 㴓 0x3d14:sè,yì # 㴔 0x3d15:jí # 㴕 0x3d16:luò # 㴖 0x3d18:mào # 㴘 0x3d19:zhá # 㴙 0x3d1a:suì # 㴚 0x3d1b:zhì # 㴛 0x3d1c:biàn # 㴜 0x3d1d:lí # 㴝 0x3d25:qiào # 㴥 0x3d26:guàn # 㴦 0x3d28:zhèn # 㴨 0x3d2a:niè # 㴪 0x3d2b:jùn # 㴫 0x3d2c:xiè # 㴬 0x3d2d:yǎo # 㴭 0x3d2e:xiè # 㴮 0x3d30:néng # 㴰 0x3d33:lǒng # 㴳 0x3d34:chén # 㴴 0x3d35:mì # 㴵 0x3d36:què # 㴶 0x3d38:nà,shǎn,yè # 㴸 0x3d3c:sù # 㴼 0x3d3d:xiè,yìn # 㴽 0x3d3e:bó # 㴾 0x3d3f:dǐng # 㴿 0x3d40:cuàn,zú # 㵀 0x3d42:chuǎng,shù # 㵂 0x3d43:shé # 㵃 0x3d44:hàn,qià,yù # 㵄 0x3d45:dàn,tàn # 㵅 0x3d46:hào # 㵆 0x3d4a:shěn,zhé # 㵊 0x3d4b:mì # 㵋 0x3d4c:chàn,qióng,xún # 㵌 0x3d4d:mèn # 㵍 0x3d4e:hǎn,jiàn,kǎn # 㵎 0x3d4f:cuǐ # 㵏 0x3d50:jué # 㵐 0x3d51:hè # 㵑 0x3d52:fèi # 㵒 0x3d53:shí # 㵓 0x3d54:chě,chè # 㵔 0x3d55:shèn # 㵕 0x3d56:nǜ # 㵖 0x3d57:fù,pán,píng # 㵗 0x3d58:màn # 㵘 0x3d5d:yì # 㵝 0x3d5e:chóu # 㵞 0x3d61:báo # 㵡 0x3d62:léi,lěi # 㵢 0x3d63:kě,luǒ # 㵣 0x3d64:diàn,shà,xiá # 㵤 0x3d65:bì,mì # 㵥 0x3d66:suí # 㵦 0x3d67:gé # 㵧 0x3d68:bì,pì # 㵨 0x3d69:yì # 㵩 0x3d6a:xián # 㵪 0x3d6b:nǐ,yì # 㵫 0x3d6c:yíng # 㵬 0x3d6d:zhǔ # 㵭 0x3d6e:chún,wěn # 㵮 0x3d6f:féng # 㵯 0x3d70:xù # 㵰 0x3d71:piǎo # 㵱 0x3d72:wǔ # 㵲 0x3d73:liáo,liú # 㵳 0x3d74:cáng # 㵴 0x3d75:zòu # 㵵 0x3d77:biàn # 㵷 0x3d78:yào,yuè # 㵸 0x3d79:huán # 㵹 0x3d7a:pái,pài # 㵺 0x3d7b:sòu # 㵻 0x3d7d:duì,lěi # 㵽 0x3d7e:jìng,qìng # 㵾 0x3d7f:xí # 㵿 0x3d81:guó # 㶁 0x3d84:yán # 㶄 0x3d85:xué # 㶅 0x3d86:chú,zhū # 㶆 0x3d87:héng # 㶇 0x3d88:yíng,yìng # 㶈 0x3d8c:lián # 㶌 0x3d8d:xiǎn # 㶍 0x3d8e:huán # 㶎 0x3d91:liàn # 㶑 0x3d92:shǎn,shěn,tàn # 㶒 0x3d93:cáng # 㶓 0x3d94:bèi # 㶔 0x3d95:jiǎn # 㶕 0x3d96:shù # 㶖 0x3d97:fàn # 㶗 0x3d98:diàn # 㶘 0x3d9a:bà # 㶚 0x3d9b:yú # 㶛 0x3d9e:nǎng # 㶞 0x3d9f:lěi # 㶟 0x3da0:yì # 㶠 0x3da1:dài,huǒ,zuó # 㶡 0x3da3:chán # 㶣 0x3da4:chǎo # 㶤 0x3da6:jìn # 㶦 0x3da7:nèn # 㶧 0x3dab:liǎo,liào # 㶫 0x3dac:méi,mò # 㶬 0x3dad:jiù,yǒu # 㶭 0x3daf:liù # 㶯 0x3db0:hán # 㶰 0x3db2:yòng # 㶲 0x3db3:jìn # 㶳 0x3db4:chǐ,shǐ # 㶴 0x3db5:rèn # 㶵 0x3db6:nóng # 㶶 0x3db9:hòng # 㶹 0x3dba:tiàn # 㶺 0x3dbf:bó # 㶿 0x3dc0:qióng # 㷀 0x3dc2:shù # 㷂 0x3dc3:cuǐ # 㷃 0x3dc4:huì # 㷄 0x3dc5:chǎo,miǎo # 㷅 0x3dc6:dòu,fù # 㷆 0x3dc7:guài,kuí # 㷇 0x3dc8:è # 㷈 0x3dc9:wèi,yù,yùn # 㷉 0x3dca:fén # 㷊 0x3dcb:tán,tǎn # 㷋 0x3dcd:lún # 㷍 0x3dce:hè,hóng,xié # 㷎 0x3dcf:yǒng # 㷏 0x3dd0:huǐ # 㷐 0x3dd2:yú # 㷒 0x3dd3:zǒng # 㷓 0x3dd4:yàn # 㷔 0x3dd5:qiú # 㷕 0x3dd6:zhào # 㷖 0x3dd7:jiǒng # 㷗 0x3dd8:tái # 㷘 0x3ddf:tuì # 㷟 0x3de0:lín # 㷠 0x3de1:jiǒng # 㷡 0x3de2:zhǎ # 㷢 0x3de4:hè,hù,xuè # 㷤 0x3de6:xù # 㷦 0x3dea:cuì,zuǎn # 㷪 0x3deb:qǐng # 㷫 0x3dec:mò # 㷬 0x3def:bèng # 㷯 0x3df0:lí # 㷰 0x3df3:yàn # 㷳 0x3df4:gé,lì # 㷴 0x3df5:mò # 㷵 0x3df6:bèi,bì # 㷶 0x3df7:juǎn # 㷷 0x3df8:dié,yè # 㷸 0x3df9:shào # 㷹 0x3dfb:wú # 㷻 0x3dfc:yàn # 㷼 0x3dfe:jué # 㷾 0x3e00:tái # 㸀 0x3e01:hǎn,hàn # 㸁 0x3e03:diǎn # 㸃 0x3e04:jì,jié # 㸄 0x3e05:jié # 㸅 0x3e09:xiè # 㸉 0x3e0a:là,lài,liè # 㸊 0x3e0b:fán # 㸋 0x3e0c:huò # 㸌 0x3e0d:xì # 㸍 0x3e0e:niè # 㸎 0x3e0f:mí # 㸏 0x3e10:rán # 㸐 0x3e11:cuàn # 㸑 0x3e12:yín # 㸒 0x3e13:mì # 㸓 0x3e15:jué # 㸕 0x3e17:tóng # 㸗 0x3e18:wàn # 㸘 0x3e1a:lǐ # 㸚 0x3e1b:sháo,shuò # 㸛 0x3e1c:kòng # 㸜 0x3e1d:kǎn # 㸝 0x3e1e:bǎn # 㸞 0x3e20:tiǎo # 㸠 0x3e22:bèi # 㸢 0x3e23:yè,yì # 㸣 0x3e24:piàn # 㸤 0x3e25:chán # 㸥 0x3e26:hù # 㸦 0x3e27:kèn,yín # 㸧 0x3e29:àn # 㸩 0x3e2a:chún # 㸪 0x3e2b:qián # 㸫 0x3e2c:bèi,fèi,pèi # 㸬 0x3e2e:fén # 㸮 0x3e30:tuó # 㸰 0x3e31:tuó # 㸱 0x3e32:zuó,zuò # 㸲 0x3e33:líng # 㸳 0x3e35:guǐ,wěi # 㸵 0x3e37:shì # 㸷 0x3e38:hǒu,ǒu,kǒu # 㸸 0x3e39:liè # 㸹 0x3e3b:sì # 㸻 0x3e3d:bèi # 㸽 0x3e3e:rèn # 㸾 0x3e3f:dú # 㸿 0x3e40:bó # 㹀 0x3e41:liáng # 㹁 0x3e42:cì,qiǎn # 㹂 0x3e43:bì,fèi # 㹃 0x3e44:jì,qì # 㹄 0x3e45:zǒng # 㹅 0x3e47:hé # 㹇 0x3e48:lí,máo # 㹈 0x3e49:yuán # 㹉 0x3e4a:yuè # 㹊 0x3e4c:chǎn,shèng # 㹌 0x3e4d:dí,dú # 㹍 0x3e4e:léi # 㹎 0x3e4f:jǐn # 㹏 0x3e50:chóng,zhòu # 㹐 0x3e51:sì,yí # 㹑 0x3e52:pǔ # 㹒 0x3e53:yì # 㹓 0x3e56:huàn # 㹖 0x3e57:táo,tāo # 㹗 0x3e58:rú,rù,ruí # 㹘 0x3e59:wěng # 㹙 0x3e5a:wěng # 㹚 0x3e5b:ráo,rǎo # 㹛 0x3e5c:yín # 㹜 0x3e5d:shì # 㹝 0x3e5e:yín,yǐn # 㹞 0x3e5f:jué # 㹟 0x3e60:tún # 㹠 0x3e61:xuán,xuàn # 㹡 0x3e64:qiè,què # 㹤 0x3e65:zhù # 㹥 0x3e68:yòu # 㹨 0x3e6b:xì,yí # 㹫 0x3e6c:shǐ # 㹬 0x3e6d:yì # 㹭 0x3e6e:mò # 㹮 0x3e71:hú,què,rǎn # 㹱 0x3e72:xiào # 㹲 0x3e73:wú # 㹳 0x3e75:jìng # 㹵 0x3e76:tíng # 㹶 0x3e77:shǐ,xìn # 㹷 0x3e78:ní # 㹸 0x3e7a:tà # 㹺 0x3e7c:chǔ,jú,yù # 㹼 0x3e7d:chǎn,shàn # 㹽 0x3e7e:piǎo # 㹾 0x3e7f:diǎo,zhào,zhuó # 㹿 0x3e80:náo # 㺀 0x3e81:nǎo # 㺁 0x3e82:gǎn,jiàn,yán # 㺂 0x3e83:gǒu # 㺃 0x3e84:yǔ # 㺄 0x3e85:hóu # 㺅 0x3e89:hù # 㺉 0x3e8a:yàng # 㺊 0x3e8c:xiàn # 㺌 0x3e8e:róng # 㺎 0x3e8f:lóu # 㺏 0x3e90:zhǎo # 㺐 0x3e91:cán,shǎn # 㺑 0x3e92:liào,yáo,xiāo # 㺒 0x3e93:piào # 㺓 0x3e94:hài,wèi # 㺔 0x3e95:fán # 㺕 0x3e96:hǎn # 㺖 0x3e97:dàn,yán # 㺗 0x3e98:zhàn # 㺘 0x3e9a:tǎ # 㺚 0x3e9b:zhù # 㺛 0x3e9c:nóng # 㺜 0x3e9d:jiàn # 㺝 0x3e9e:yú # 㺞 0x3e9f:zhuó # 㺟 0x3ea0:yòu,yù # 㺠 0x3ea1:lì # 㺡 0x3ea5:chán,tán # 㺥 0x3ea6:lián # 㺦 0x3ea9:jiù,sè # 㺩 0x3eaa:pú # 㺪 0x3eab:qiú # 㺫 0x3eac:gǒng # 㺬 0x3ead:zǐ # 㺭 0x3eae:yú # 㺮 0x3eb1:réng # 㺱 0x3eb2:niǔ # 㺲 0x3eb3:méi # 㺳 0x3eb5:jiú # 㺵 0x3eb7:xù # 㺷 0x3eb8:píng # 㺸 0x3eb9:biàn # 㺹 0x3eba:mào # 㺺 0x3ebf:yí # 㺿 0x3ec0:yóu,yú # 㻀 0x3ec2:píng # 㻂 0x3ec4:bǎo # 㻄 0x3ec5:huì,kuài # 㻅 0x3ec9:bù # 㻉 0x3eca:máng,mén,mèng # 㻊 0x3ecb:là,lèi # 㻋 0x3ecc:tú # 㻌 0x3ecd:wú # 㻍 0x3ece:lì,sè # 㻎 0x3ecf:líng,lǐng # 㻏 0x3ed1:jì # 㻑 0x3ed2:jùn # 㻒 0x3ed4:duǒ,ruì # 㻔 0x3ed5:jué # 㻕 0x3ed6:dài # 㻖 0x3ed7:bèi # 㻗 0x3edd:là # 㻝 0x3ede:bīn,bān # 㻞 0x3edf:suí # 㻟 0x3ee0:tú # 㻠 0x3ee1:dié,jué # 㻡 0x3ee7:duò,hé # 㻧 0x3eea:suì # 㻪 0x3eeb:bì # 㻫 0x3eec:tú # 㻬 0x3eed:sè,zé # 㻭 0x3eee:càn # 㻮 0x3eef:tú # 㻯 0x3ef0:miǎn,rè,wèi,yù # 㻰 0x3ef2:lǚ # 㻲 0x3ef5:zhàn # 㻵 0x3ef6:bǐ,bì # 㻶 0x3ef7:jí # 㻷 0x3ef8:cén,jìn,xín,zēn # 㻸 0x3efa:lì,liè # 㻺 0x3efd:suì # 㻽 0x3eff:shǔ # 㻿 0x3f02:é,wèn,yuǎn # 㼂 0x3f07:qióng # 㼇 0x3f08:luó # 㼈 0x3f09:yìn,zhèn # 㼉 0x3f0a:tún # 㼊 0x3f0b:gǔ,jiǔ,móu,rǔ # 㼋 0x3f0c:yǔ # 㼌 0x3f0d:lěi # 㼍 0x3f0e:bèi,bó,kě # 㼎 0x3f0f:něi # 㼏 0x3f10:pián # 㼐 0x3f11:liàn,luán # 㼑 0x3f12:qiǔ,tǎng # 㼒 0x3f13:lián,liǎn # 㼓 0x3f16:lì # 㼖 0x3f17:dǐng,tíng # 㼗 0x3f18:wǎ # 㼘 0x3f19:zhòu # 㼙 0x3f1b:xíng # 㼛 0x3f1c:àng,póu # 㼜 0x3f1d:fàn,wǎn # 㼝 0x3f1e:pèng # 㼞 0x3f1f:bái # 㼟 0x3f20:tuó # 㼠 0x3f22:ě,yí # 㼢 0x3f23:bǎi,bó # 㼣 0x3f24:qì,qiè,yà # 㼤 0x3f25:chú,kǎo,tǒu # 㼥 0x3f26:gǒng # 㼦 0x3f27:tóng # 㼧 0x3f28:hán # 㼨 0x3f29:chéng # 㼩 0x3f2a:jiá # 㼪 0x3f2b:huàn # 㼫 0x3f2c:xìng # 㼬 0x3f2d:diàn,niǎo # 㼭 0x3f2e:chāi,qì # 㼮 0x3f2f:dòng # 㼯 0x3f30:é,pí # 㼰 0x3f31:ruǎn # 㼱 0x3f32:liè # 㼲 0x3f33:shěng # 㼳 0x3f34:ǒu # 㼴 0x3f35:dì # 㼵 0x3f36:yú # 㼶 0x3f37:chuán # 㼷 0x3f38:róng # 㼸 0x3f3a:táng # 㼺 0x3f3b:cóng # 㼻 0x3f3c:piáo # 㼼 0x3f3d:shuǎng,chuǎng # 㼽 0x3f3e:lù # 㼾 0x3f3f:tóng # 㼿 0x3f40:zhèng # 㽀 0x3f41:lì # 㽁 0x3f42:sà # 㽂 0x3f47:guài,hú,huí,méng,sè # 㽇 0x3f48:yì # 㽈 0x3f49:hǎn,jiàn,xiàn # 㽉 0x3f4a:xiè # 㽊 0x3f4b:luó,luò # 㽋 0x3f4c:liù # 㽌 0x3f4e:dǎn,tán # 㽎 0x3f51:tán # 㽑 0x3f55:yóu # 㽕 0x3f56:nán # 㽖 0x3f58:gǎng # 㽘 0x3f59:jùn # 㽙 0x3f5a:chì # 㽚 0x3f5b:gōu,qú # 㽛 0x3f5c:wǎn # 㽜 0x3f5d:lì # 㽝 0x3f5e:liú # 㽞 0x3f5f:liè # 㽟 0x3f60:xiá # 㽠 0x3f62:ǎn,yè # 㽢 0x3f63:yù # 㽣 0x3f64:jú # 㽤 0x3f65:róu # 㽥 0x3f66:xún # 㽦 0x3f68:cuó # 㽨 0x3f69:càn,cào # 㽩 0x3f6a:zěng,zhǎ # 㽪 0x3f6b:yǒng # 㽫 0x3f6c:fù # 㽬 0x3f6d:ruǎn # 㽭 0x3f6f:xí # 㽯 0x3f70:shù # 㽰 0x3f71:jiǎo,jiū,niú # 㽱 0x3f72:jiǎo # 㽲 0x3f73:hàn,xiè,xǔ,yú # 㽳 0x3f74:zhàng # 㽴 0x3f77:shuì # 㽷 0x3f78:chén # 㽸 0x3f79:fàn,wǎn # 㽹 0x3f7a:jí # 㽺 0x3f7d:gù # 㽽 0x3f7e:wù # 㽾 0x3f80:qiè # 㾀 0x3f81:shù # 㾁 0x3f83:tuó # 㾃 0x3f84:dú # 㾄 0x3f85:zǐ # 㾅 0x3f86:rán,shǎn # 㾆 0x3f87:mù # 㾇 0x3f88:fù # 㾈 0x3f89:líng # 㾉 0x3f8a:jí # 㾊 0x3f8b:xiù # 㾋 0x3f8c:xuǎn # 㾌 0x3f8d:nái # 㾍 0x3f8f:jiè # 㾏 0x3f90:lì # 㾐 0x3f91:dá # 㾑 0x3f92:jì,rú,rù # 㾒 0x3f94:lǚ # 㾔 0x3f95:shěn # 㾕 0x3f96:lǐ,luó # 㾖 0x3f97:lǎng,liàng # 㾗 0x3f98:gěng # 㾘 0x3f99:yǐn # 㾙 0x3f9b:qǐn # 㾛 0x3f9c:qiè # 㾜 0x3f9d:chè # 㾝 0x3f9e:yǒu # 㾞 0x3f9f:bù # 㾟 0x3fa0:huáng,kuáng,kuì # 㾠 0x3fa1:què # 㾡 0x3fa2:lài # 㾢 0x3fa5:xù # 㾥 0x3fa6:bàng,pèi,pén # 㾦 0x3fa7:kè # 㾧 0x3fa8:qǐ,yǐ # 㾨 0x3faa:shěng # 㾪 0x3fad:zhòu # 㾭 0x3fae:huáng # 㾮 0x3faf:tuí,wěi # 㾯 0x3fb0:hú # 㾰 0x3fb1:bèi,fàn,fèi,fú # 㾱 0x3fb5:jì # 㾵 0x3fb6:gǔ # 㾶 0x3fb8:gǎo # 㾸 0x3fb9:chái # 㾹 0x3fba:mà,mò # 㾺 0x3fbb:zhù # 㾻 0x3fbc:tuǐ # 㾼 0x3fbd:tuí,zhuì # 㾽 0x3fbe:lián # 㾾 0x3fbf:láng,lǎng # 㾿 0x3fc3:dài,zhì # 㿃 0x3fc4:ài # 㿄 0x3fc5:xiǎn,xuǎn # 㿅 0x3fc7:xí,xì # 㿇 0x3fc9:tuí # 㿉 0x3fca:cǎn # 㿊 0x3fcb:sào # 㿋 0x3fcd:jiè # 㿍 0x3fce:fèn # 㿎 0x3fcf:qún # 㿏 0x3fd1:yào # 㿑 0x3fd2:dǎo # 㿒 0x3fd3:jiá # 㿓 0x3fd4:lěi # 㿔 0x3fd5:yán # 㿕 0x3fd6:lú # 㿖 0x3fd7:tuí # 㿗 0x3fd8:yíng # 㿘 0x3fd9:pì # 㿙 0x3fda:luò # 㿚 0x3fdb:lí,lì # 㿛 0x3fdc:biě # 㿜 0x3fde:mào # 㿞 0x3fdf:bái,jiǎo # 㿟 0x3fe2:yào,zhuì # 㿢 0x3fe3:hé,xiá # 㿣 0x3fe4:chǔn # 㿤 0x3fe5:hú,hé # 㿥 0x3fe6:nìng # 㿦 0x3fe7:chóu # 㿧 0x3fe8:lì # 㿨 0x3fe9:tǎng # 㿩 0x3fea:huán # 㿪 0x3feb:bì # 㿫 0x3fed:chè # 㿭 0x3fee:yàng # 㿮 0x3fef:dá # 㿯 0x3ff0:áo # 㿰 0x3ff1:xué # 㿱 0x3ff5:rǎn # 㿵 0x3ff7:cuó,cāo # 㿷 0x3ff8:wǎn,mán # 㿸 0x3ff9:tà # 㿹 0x3ffa:báo # 㿺 0x3ffc:yán # 㿼 0x3ffe:zhù # 㿾 0x3fff:yǎ # 㿿 0x4000:fán # 䀀 0x4001:yòu # 䀁 0x4003:tuí # 䀃 0x4004:méng # 䀄 0x4005:shè,zhé # 䀅 0x4006:jìn # 䀆 0x4007:gǔ,què # 䀇 0x4008:qì # 䀈 0x4009:qiáo,shà # 䀉 0x400a:jiǎo # 䀊 0x400b:yán # 䀋 0x400d:kàn # 䀍 0x400e:miǎn # 䀎 0x400f:xiàn,xuàn # 䀏 0x4010:sǎn # 䀐 0x4011:nà,nì,wò # 䀑 0x4013:huàn # 䀓 0x4014:niú,rèn # 䀔 0x4015:chèng,zhèn # 䀕 0x4017:jué # 䀗 0x4018:xí,xié # 䀘 0x4019:qì # 䀙 0x401a:áng # 䀚 0x401b:mèi,wù # 䀛 0x401c:gǔ,mèi,xué # 䀜 0x401f:fán,fèi,fèn # 䀟 0x4020:qú,jù # 䀠 0x4021:chàn,tàn # 䀡 0x4022:shùn # 䀢 0x4023:bì,mà # 䀣 0x4024:mào # 䀤 0x4025:shuò # 䀥 0x4026:gǔ # 䀦 0x4027:hǒng # 䀧 0x4028:huàn # 䀨 0x4029:luò # 䀩 0x402a:háng # 䀪 0x402b:jiá # 䀫 0x402c:quán # 䀬 0x402e:máng # 䀮 0x402f:bǔ # 䀯 0x4030:gǔ,yíng # 䀰 0x4032:mù # 䀲 0x4033:ài,là,lài # 䀳 0x4034:yǐng # 䀴 0x4035:shùn # 䀵 0x4036:lǎng,liàng # 䀶 0x4037:jié # 䀷 0x4038:dì,zhì # 䀸 0x4039:jiá,shè,jié # 䀹 0x403b:pìn # 䀻 0x403c:rèn,zhěn # 䀼 0x403d:yán # 䀽 0x403e:dǔ # 䀾 0x403f:dì # 䀿 0x4041:lǎng,liàng # 䁁 0x4042:xiàn # 䁂 0x4044:xìng # 䁄 0x4045:bèi,bì,měng,mèng # 䁅 0x4046:ǎn,yì # 䁆 0x4047:mì # 䁇 0x4048:qì # 䁈 0x4049:qì # 䁉 0x404a:wò # 䁊 0x404b:shé # 䁋 0x404c:yù # 䁌 0x404d:jià,kè,qià # 䁍 0x404e:chéng # 䁎 0x404f:yǎo # 䁏 0x4050:yìng # 䁐 0x4051:yáng # 䁑 0x4052:jí # 䁒 0x4053:jiè,zǒng # 䁓 0x4054:hàn,huǎn,xuān # 䁔 0x4055:mín # 䁕 0x4056:lōu # 䁖 0x4057:kǎi # 䁗 0x4058:yǎo # 䁘 0x4059:yǎn,yàn # 䁙 0x405a:sǔn # 䁚 0x405b:guǐ,guì,kuì # 䁛 0x405c:huǎng,huàng # 䁜 0x405d:yíng # 䁝 0x405e:shěng # 䁞 0x405f:chá,duó # 䁟 0x4060:lián # 䁠 0x4062:xuán # 䁢 0x4063:chuán # 䁣 0x4064:chè,chèng # 䁤 0x4065:nì # 䁥 0x4066:qù # 䁦 0x4067:miáo # 䁧 0x4068:huò # 䁨 0x4069:yú # 䁩 0x406a:nǎn,zhǎn # 䁪 0x406b:hú # 䁫 0x406c:céng # 䁬 0x406e:qián # 䁮 0x406f:shè,xié # 䁯 0x4070:jiǎng # 䁰 0x4071:kōu # 䁱 0x4072:mái # 䁲 0x4073:mǎng # 䁳 0x4074:zhǎn # 䁴 0x4075:biǎn # 䁵 0x4076:jiǎo # 䁶 0x4077:jué,wò # 䁷 0x4078:nóng # 䁸 0x4079:bì # 䁹 0x407a:shì # 䁺 0x407b:lì,shuò # 䁻 0x407c:mò,mù # 䁼 0x407d:liè # 䁽 0x407e:miè # 䁾 0x407f:mò # 䁿 0x4080:xī # 䂀 0x4081:chán # 䂁 0x4082:qú # 䂂 0x4083:jiào,jié # 䂃 0x4084:huò,kuàng # 䂄 0x4086:xù # 䂆 0x4087:náng,niǔ,nǒng,páng # 䂇 0x4088:tóng # 䂈 0x4089:hóu # 䂉 0x408a:yù # 䂊 0x408d:bó # 䂍 0x408e:zuǎn # 䂎 0x4090:chuò # 䂐 0x4092:jié,qià,yà # 䂒 0x4094:xìng # 䂔 0x4095:huì # 䂕 0x4096:shí,sì # 䂖 0x409a:yáo,yóu # 䂚 0x409b:yú # 䂛 0x409c:bàng,péi # 䂜 0x409d:jié,zé,zhé # 䂝 0x409e:zhè # 䂞 0x40a0:shé,shǐ # 䂠 0x40a1:dǐ,zhǐ # 䂡 0x40a2:dǒng # 䂢 0x40a3:cí # 䂣 0x40a4:fù,hái # 䂤 0x40a5:mín # 䂥 0x40a6:zhěn # 䂦 0x40a7:zhěn # 䂧 0x40a9:yàn # 䂩 0x40aa:diào,tiǎo # 䂪 0x40ab:hóng # 䂫 0x40ac:gǒng # 䂬 0x40ae:lüè # 䂮 0x40af:guài,guàn # 䂯 0x40b0:là # 䂰 0x40b1:cuì,ruì # 䂱 0x40b2:fǎ # 䂲 0x40b3:cuǒ # 䂳 0x40b4:yán # 䂴 0x40b6:jié # 䂶 0x40b8:guó,xù # 䂸 0x40b9:suǒ # 䂹 0x40ba:wǎn,wǒ # 䂺 0x40bb:zhèng # 䂻 0x40bc:niè # 䂼 0x40bd:diào,yì # 䂽 0x40be:lǎi # 䂾 0x40bf:tà,tiè # 䂿 0x40c0:cuì,xùn # 䃀 0x40c2:gǔn,gùn # 䃂 0x40c7:mián # 䃇 0x40c9:mín # 䃉 0x40ca:jǔ # 䃊 0x40cb:yú # 䃋 0x40cd:zhào,zhuì # 䃍 0x40ce:zhǎ # 䃎 0x40d1:pán # 䃑 0x40d2:hé # 䃒 0x40d3:gòu # 䃓 0x40d4:hóng # 䃔 0x40d5:láo,luò # 䃕 0x40d6:wù # 䃖 0x40d7:chuò # 䃗 0x40d9:lù # 䃙 0x40da:cù # 䃚 0x40db:lián,qiàn # 䃛 0x40dd:qiào # 䃝 0x40de:shú,yì # 䃞 0x40e1:cén # 䃡 0x40e3:huǐ # 䃣 0x40e4:sù # 䃤 0x40e5:chuáng # 䃥 0x40e7:lóng # 䃧 0x40e9:náo # 䃩 0x40ea:tán # 䃪 0x40eb:dǎn # 䃫 0x40ec:wěi # 䃬 0x40ed:gǎn # 䃭 0x40ee:dá # 䃮 0x40ef:lì # 䃯 0x40f1:xiàn # 䃱 0x40f2:pán,pàn # 䃲 0x40f3:là # 䃳 0x40f5:niǎo # 䃵 0x40f6:huái # 䃶 0x40f7:yíng # 䃷 0x40f8:xiàn # 䃸 0x40f9:làn,lǎng # 䃹 0x40fa:mó,mò # 䃺 0x40fb:bà,pái # 䃻 0x40fd:fú,guǐ,sì # 䃽 0x40fe:bǐ # 䃾 0x4100:huò # 䄀 0x4101:yì # 䄁 0x4102:liù # 䄂 0x4105:juàn # 䄅 0x4106:huó,kuò # 䄆 0x4107:chéng # 䄇 0x4108:dòu # 䄈 0x4109:é # 䄉 0x410b:yǎn # 䄋 0x410c:zhuì # 䄌 0x410d:dù,duó,zhà # 䄍 0x410e:qǐ # 䄎 0x410f:yú,yāo # 䄏 0x4110:quàn # 䄐 0x4111:huó,kuò # 䄑 0x4112:niè,rěn # 䄒 0x4113:héng,huáng # 䄓 0x4114:jǔ # 䄔 0x4115:shè,shèn,tiǎn # 䄕 0x4118:péng # 䄘 0x4119:míng # 䄙 0x411a:cáo # 䄚 0x411b:lóu # 䄛 0x411c:lí,chī # 䄜 0x411d:chǔn # 䄝 0x411f:cuì # 䄟 0x4120:shàn # 䄠 0x4122:qí # 䄢 0x4124:lài,lán # 䄤 0x4125:líng # 䄥 0x4126:liǎo # 䄦 0x4127:réng,rǒng # 䄧 0x4128:yú,yǔ # 䄨 0x4129:náo,yì # 䄩 0x412a:chuò,diǎo # 䄪 0x412b:qǐ # 䄫 0x412c:yí # 䄬 0x412d:nián # 䄭 0x412f:jiǎn,xiàn # 䄯 0x4130:yá,zhá # 䄰 0x4132:chuí # 䄲 0x4136:bì # 䄶 0x4137:dàn,diǎo,shí # 䄷 0x4138:pò # 䄸 0x4139:nián,tiǎn # 䄹 0x413a:zhì # 䄺 0x413b:cháo,táo,zhào # 䄻 0x413c:tiǎn # 䄼 0x413d:tiǎn # 䄽 0x413e:ròu # 䄾 0x413f:yì # 䄿 0x4140:liè # 䅀 0x4141:àn # 䅁 0x4142:hé # 䅂 0x4143:qióng # 䅃 0x4144:lì # 䅄 0x4146:zì # 䅆 0x4147:sù # 䅇 0x4148:yuàn # 䅈 0x4149:yà # 䅉 0x414a:dù # 䅊 0x414b:wǎn # 䅋 0x414d:dòng,tǐng # 䅍 0x414e:yǒu # 䅎 0x414f:huì,wèi # 䅏 0x4150:jiǎn,qián # 䅐 0x4151:ruí,suí # 䅑 0x4152:máng # 䅒 0x4153:jǔ,qù # 䅓 0x4156:ǎn # 䅖 0x4157:suì # 䅗 0x4158:lái # 䅘 0x4159:hùn # 䅙 0x415a:qiǎng,quǎn,zé # 䅚 0x415c:duò # 䅜 0x415e:nà,nài,nè # 䅞 0x415f:cǎn # 䅟 0x4160:tí # 䅠 0x4161:xǔ # 䅡 0x4162:jiù # 䅢 0x4163:huáng # 䅣 0x4164:qì # 䅤 0x4165:jié # 䅥 0x4166:máo # 䅦 0x4167:yàn # 䅧 0x4169:zhǐ # 䅩 0x416a:tuí # 䅪 0x416c:ài,yǎn,yè # 䅬 0x416d:páng # 䅭 0x416e:càng # 䅮 0x416f:táng # 䅯 0x4170:ěn # 䅰 0x4171:hùn # 䅱 0x4172:qí # 䅲 0x4173:chú # 䅳 0x4174:suǒ # 䅴 0x4175:zhuó # 䅵 0x4176:nòu,wǔ # 䅶 0x4177:tú # 䅷 0x4178:zú # 䅸 0x4179:lóu,lǒu # 䅹 0x417a:miǎo # 䅺 0x417b:lí # 䅻 0x417c:mán # 䅼 0x417d:gǔ # 䅽 0x417e:cén,qián,qín # 䅾 0x417f:huá # 䅿 0x4180:měi # 䆀 0x4182:lián,qiàn # 䆂 0x4183:dǎo,dào # 䆃 0x4184:shàn # 䆄 0x4185:cí,jǐ,zī # 䆅 0x4188:zhì # 䆈 0x4189:bà # 䆉 0x418a:cuì # 䆊 0x418b:qiū # 䆋 0x418d:lóng # 䆍 0x418f:fèi # 䆏 0x4190:guó # 䆐 0x4191:chéng # 䆑 0x4192:jiù # 䆒 0x4193:è,ruǎn # 䆓 0x4195:jué,yuè # 䆕 0x4196:hóng # 䆖 0x4197:jiào # 䆗 0x4198:cuán,yā # 䆘 0x4199:yáo # 䆙 0x419a:tóng # 䆚 0x419b:chá,zhà,zhé # 䆛 0x419c:yòu # 䆜 0x419d:shù # 䆝 0x419e:yǎo # 䆞 0x419f:gé # 䆟 0x41a0:huàn # 䆠 0x41a1:láng,làng # 䆡 0x41a2:jué,yuè # 䆢 0x41a3:chén # 䆣 0x41a6:shèn # 䆦 0x41a8:míng # 䆨 0x41a9:míng # 䆩 0x41ab:chuāng # 䆫 0x41ac:yǔn # 䆬 0x41ae:jìn # 䆮 0x41af:chuò,zhuó # 䆯 0x41b1:tǎn # 䆱 0x41b3:qióng,suì # 䆳 0x41b5:chéng # 䆵 0x41b7:yù,xuè # 䆷 0x41b8:chéng # 䆸 0x41b9:tǒng # 䆹 0x41bb:qiào # 䆻 0x41bd:jù,qú,qún # 䆽 0x41be:lán # 䆾 0x41bf:yì # 䆿 0x41c0:róng,rǒng # 䇀 0x41c3:sì,xiào # 䇃 0x41c5:fá # 䇅 0x41c7:méng # 䇇 0x41c8:guì,huà # 䇈 0x41cb:hài,rǎn,xiè # 䇋 0x41cc:qiào # 䇌 0x41cd:chuò # 䇍 0x41ce:què # 䇎 0x41cf:duì # 䇏 0x41d0:lì # 䇐 0x41d1:bà # 䇑 0x41d2:jiè,qín,xiàn # 䇒 0x41d4:luò,nuò # 䇔 0x41d6:yǔn # 䇖 0x41d8:hù # 䇘 0x41d9:yǐn # 䇙 0x41db:zhǐ # 䇛 0x41dc:liǎn # 䇜 0x41de:gǎn # 䇞 0x41df:jiàn # 䇟 0x41e0:zhòu,zhù # 䇠 0x41e1:zhù # 䇡 0x41e2:kǔ # 䇢 0x41e3:nà,nèi,yǐ # 䇣 0x41e4:duì,ruì,sù # 䇤 0x41e5:zé,zuó # 䇥 0x41e6:yǎng # 䇦 0x41e7:zhù # 䇧 0x41e8:gòng,xiáng # 䇨 0x41e9:yì # 䇩 0x41ec:chuǎng,zhū # 䇬 0x41ed:lǎo # 䇭 0x41ee:rèn # 䇮 0x41ef:róng # 䇯 0x41f1:nà # 䇱 0x41f2:cè,jiā # 䇲 0x41f5:yí # 䇵 0x41f6:jué # 䇶 0x41f7:bǐ,bié # 䇷 0x41f8:chéng,shèng,zèng # 䇸 0x41f9:jùn # 䇹 0x41fa:chóu,dòu # 䇺 0x41fb:huì,kuì,wěi # 䇻 0x41fc:chì,yì # 䇼 0x41fd:zhì # 䇽 0x41fe:yán # 䇾 0x4201:lún,luò # 䈁 0x4202:bìng,píng # 䈂 0x4203:zhǎo # 䈃 0x4204:hán # 䈄 0x4205:yù # 䈅 0x4206:dài # 䈆 0x4207:zhào # 䈇 0x4208:féi # 䈈 0x4209:shà # 䈉 0x420a:líng # 䈊 0x420b:tà # 䈋 0x420d:máng # 䈍 0x420e:yè # 䈎 0x420f:báo # 䈏 0x4210:kuì # 䈐 0x4211:guǎ,jué # 䈑 0x4212:nǎn # 䈒 0x4213:gé # 䈓 0x4215:chí,shi,tí,shí # 䈕 0x4217:suǒ # 䈗 0x4218:cí # 䈘 0x4219:zhòu # 䈙 0x421a:tái # 䈚 0x421b:kuài # 䈛 0x421c:qìn # 䈜 0x421e:dǔ # 䈞 0x421f:cè # 䈟 0x4220:huǎn # 䈠 0x4222:sǎi # 䈢 0x4223:zhèng # 䈣 0x4224:qián # 䈤 0x4227:wěi # 䈧 0x422a:xì # 䈪 0x422b:nà # 䈫 0x422c:pú # 䈬 0x422d:huái # 䈭 0x422e:jǔ,jù,wǎn # 䈮 0x4232:pán # 䈲 0x4233:tà # 䈳 0x4234:qiàn,zhǎn # 䈴 0x4236:róng # 䈶 0x4237:luò # 䈷 0x4238:hú # 䈸 0x4239:sǒu # 䈹 0x423b:pú # 䈻 0x423c:miè,mì # 䈼 0x423e:shāo,shuò # 䈾 0x423f:mài,mì # 䈿 0x4240:shù # 䉀 0x4241:líng # 䉁 0x4242:lěi # 䉂 0x4243:jiǎng # 䉃 0x4244:léng # 䉄 0x4245:zhì # 䉅 0x4246:diǎo # 䉆 0x4248:sǎn # 䉈 0x4249:hú # 䉉 0x424a:fàn,fáng # 䉊 0x424b:mèi # 䉋 0x424c:suì # 䉌 0x424d:jiǎn # 䉍 0x424e:táng # 䉎 0x424f:xiè # 䉏 0x4251:mó,wú # 䉑 0x4252:fán # 䉒 0x4253:léi,luò # 䉓 0x4255:céng # 䉕 0x4256:líng # 䉖 0x4258:cóng # 䉘 0x4259:yún # 䉙 0x425a:méng # 䉚 0x425b:yù # 䉛 0x425c:zhì # 䉜 0x425d:qǐ # 䉝 0x425e:dǎn # 䉞 0x425f:huò # 䉟 0x4260:wéi # 䉠 0x4261:tán # 䉡 0x4262:sè # 䉢 0x4263:xiè # 䉣 0x4264:sǒu # 䉤 0x4265:sǒng # 䉥 0x4267:liú,liǔ # 䉧 0x4268:yì # 䉨 0x426a:lèi # 䉪 0x426b:lí # 䉫 0x426c:fèi # 䉬 0x426d:liè # 䉭 0x426e:lìn # 䉮 0x426f:xiàn # 䉯 0x4270:yáo # 䉰 0x4272:biè,mí # 䉲 0x4273:xiǎn # 䉳 0x4274:ráng,rǎng # 䉴 0x4275:zhuàn # 䉵 0x4277:dàn,jìn,yán # 䉷 0x4278:biàn # 䉸 0x4279:líng,liǔ # 䉹 0x427a:hóng # 䉺 0x427b:qí # 䉻 0x427c:liào # 䉼 0x427d:bǎn # 䉽 0x427e:mì,bì # 䉾 0x427f:hú,luò # 䉿 0x4280:hú # 䊀 0x4282:cè,sè # 䊂 0x4283:pèi # 䊃 0x4284:qióng # 䊄 0x4285:míng # 䊅 0x4286:jiù,qiǔ # 䊆 0x4287:bù # 䊇 0x4288:méi # 䊈 0x4289:sǎn # 䊉 0x428a:mèi # 䊊 0x428d:lí # 䊍 0x428e:quǎn # 䊎 0x4290:èn,huá,huàn,hún # 䊐 0x4291:xiǎng # 䊑 0x4293:shì # 䊓 0x4296:lǎn,nǎn # 䊖 0x4297:huáng,huǎng # 䊗 0x4298:jiù # 䊘 0x4299:yán # 䊙 0x429b:sǎ # 䊛 0x429c:tuán # 䊜 0x429d:xiè # 䊝 0x429e:zhé # 䊞 0x429f:mén # 䊟 0x42a0:xì # 䊠 0x42a1:mán # 䊡 0x42a3:huáng # 䊣 0x42a4:tán # 䊤 0x42a5:xiào # 䊥 0x42a6:yá,yè # 䊦 0x42a7:bì # 䊧 0x42a8:luó # 䊨 0x42a9:fán,fàn # 䊩 0x42aa:lì # 䊪 0x42ab:cuǐ,mí # 䊫 0x42ac:chà # 䊬 0x42ad:chóu,dào # 䊭 0x42ae:dí,zhé,zhè # 䊮 0x42af:kuàng # 䊯 0x42b0:chǔ # 䊰 0x42b2:chǎn # 䊲 0x42b3:mí # 䊳 0x42b4:qiàn # 䊴 0x42b5:qiú # 䊵 0x42b6:zhèn # 䊶 0x42ba:gǔ,hù # 䊺 0x42bb:yǎn # 䊻 0x42bc:chǐ # 䊼 0x42bd:guài # 䊽 0x42be:mù # 䊾 0x42bf:bó,kù # 䊿 0x42c0:kuà,huà # 䋀 0x42c1:gěng # 䋁 0x42c2:yáo # 䋂 0x42c3:mào # 䋃 0x42c4:wǎng # 䋄 0x42c8:rú # 䋈 0x42c9:jué,kě,xué # 䋉 0x42cb:mín # 䋋 0x42cc:jiǎng # 䋌 0x42ce:zhàn # 䋎 0x42cf:zuò # 䋏 0x42d0:yuè # 䋐 0x42d1:bǐng # 䋑 0x42d3:zhòu # 䋓 0x42d4:bì # 䋔 0x42d5:rèn # 䋕 0x42d6:yù # 䋖 0x42d8:chuò,zhuì # 䋘 0x42d9:ěr # 䋙 0x42da:yì # 䋚 0x42db:mí,mǐ # 䋛 0x42dc:qìng # 䋜 0x42de:wǎng # 䋞 0x42df:jì # 䋟 0x42e0:bǔ # 䋠 0x42e2:biè,biē # 䋢 0x42e3:fán,pán # 䋣 0x42e4:yào,yuè # 䋤 0x42e5:lí # 䋥 0x42e6:fán # 䋦 0x42e7:qú # 䋧 0x42e8:fǔ # 䋨 0x42e9:ér # 䋩 0x42ed:huò,yù # 䋭 0x42ee:jìn,qián # 䋮 0x42ef:qǐ,qìng # 䋯 0x42f0:jú # 䋰 0x42f1:lái # 䋱 0x42f2:chě,shéng,xǐng,zhè # 䋲 0x42f3:bèi,mì # 䋳 0x42f4:niù,rǒng,róu,rǔ # 䋴 0x42f5:yì # 䋵 0x42f6:xù # 䋶 0x42f7:liú,móu # 䋷 0x42f8:xún # 䋸 0x42f9:fú,fù # 䋹 0x42fb:nín # 䋻 0x42fc:tǐng,yíng,tīng # 䋼 0x42fd:běng,pěng # 䋽 0x42fe:zhǎ # 䋾 0x4302:òu # 䌂 0x4303:shuò # 䌃 0x4304:gěng # 䌄 0x4305:táng # 䌅 0x4306:guì # 䌆 0x4307:suǒ # 䌇 0x4308:tà # 䌈 0x430a:yáo,yóu # 䌊 0x430c:qì,qiè,qǔ # 䌌 0x430d:hàn,jǐn # 䌍 0x430e:lüè # 䌎 0x430f:mì,miàn # 䌏 0x4310:mì # 䌐 0x4312:lù # 䌒 0x4313:fán # 䌓 0x4314:òu # 䌔 0x4315:mí,mó # 䌕 0x4316:jié # 䌖 0x4317:fǔ # 䌗 0x4318:mí # 䌘 0x4319:huǎng # 䌙 0x431a:sù # 䌚 0x431b:yáo # 䌛 0x431c:niè # 䌜 0x431d:jìn # 䌝 0x431e:liǎn # 䌞 0x431f:bì # 䌟 0x4320:qìng,yǎn,yìn # 䌠 0x4321:tǐ # 䌡 0x4322:líng # 䌢 0x4323:zuǎn # 䌣 0x4324:zhǐ # 䌤 0x4325:yǐn # 䌥 0x4326:dǎo # 䌦 0x4327:chóu # 䌧 0x4328:cài # 䌨 0x4329:mì,miè # 䌩 0x432a:yán # 䌪 0x432b:lǎn # 䌫 0x432c:chóng # 䌬 0x432f:guàn,quán # 䌯 0x4330:shè # 䌰 0x4331:luò # 䌱 0x4334:luò # 䌴 0x4335:zhú,zhǔ # 䌵 0x4337:chōu,chóu # 䌷 0x4338:juàn # 䌸 0x4339:jiǒng # 䌹 0x433a:ěr # 䌺 0x433b:yì # 䌻 0x433c:ruì # 䌼 0x433d:cǎi # 䌽 0x433e:rén # 䌾 0x433f:fú # 䌿 0x4340:lán # 䍀 0x4341:suì # 䍁 0x4342:yú # 䍂 0x4343:yáo,yóu # 䍃 0x4344:diǎn # 䍄 0x4345:líng # 䍅 0x4346:zhù # 䍆 0x4347:tà # 䍇 0x4348:píng # 䍈 0x4349:qián,zhǎi # 䍉 0x434a:jué # 䍊 0x434b:chuí # 䍋 0x434c:bù,fú # 䍌 0x434d:gǔ,gù,guàng,kòu # 䍍 0x434e:cùn # 䍎 0x4350:hǎn,hàn # 䍐 0x4351:hǎn # 䍑 0x4352:mǒu # 䍒 0x4353:hù,yá # 䍓 0x4354:hóng # 䍔 0x4355:dǐ # 䍕 0x4356:fú,fù,hài,xiè # 䍖 0x4357:xuàn # 䍗 0x4358:mí # 䍘 0x4359:méi # 䍙 0x435a:làng # 䍚 0x435b:gù # 䍛 0x435c:zhào # 䍜 0x435d:tà,zǎn # 䍝 0x435e:yù # 䍞 0x435f:zòng # 䍟 0x4360:lí # 䍠 0x4361:liào,lù # 䍡 0x4362:wú,wǔ # 䍢 0x4363:léi # 䍣 0x4364:jǐ # 䍤 0x4365:lèi,lì # 䍥 0x4366:lí # 䍦 0x4368:bó,fèi # 䍨 0x4369:ǎng,yǎng # 䍩 0x436a:kuì,wà # 䍪 0x436b:tuó # 䍫 0x436e:zhào # 䍮 0x436f:guǐ,jì # 䍯 0x4371:xú # 䍱 0x4372:nái,ní,nì # 䍲 0x4373:chuò,jué,què # 䍳 0x4374:duò,ruí,wěi,wèi # 䍴 0x4376:dòng # 䍶 0x4377:guì,huì,wěi # 䍷 0x4378:bó # 䍸 0x437a:huán # 䍺 0x437b:xuǎn # 䍻 0x437c:cán # 䍼 0x437d:lì # 䍽 0x437e:tuí,yǎn # 䍾 0x437f:huáng # 䍿 0x4380:xuè,yuè # 䎀 0x4381:hú # 䎁 0x4382:bǎo # 䎂 0x4383:rǎn # 䎃 0x4384:tiáo # 䎄 0x4385:fù,luò,pò # 䎅 0x4386:liào # 䎆 0x4388:yì # 䎈 0x4389:shù,yù # 䎉 0x438a:pò # 䎊 0x438b:hè,kào # 䎋 0x438c:cù # 䎌 0x438e:nà # 䎎 0x438f:àn,hán # 䎏 0x4390:chǎo # 䎐 0x4391:lù # 䎑 0x4392:zhǎn # 䎒 0x4393:tà # 䎓 0x4397:qiáo # 䎗 0x4398:sù # 䎘 0x439a:guàn,huì # 䎚 0x439d:chú,zhù # 䎝 0x439f:ér,nuò # 䎟 0x43a0:ér,nuó # 䎠 0x43a1:nuǎn,ruǎn # 䎡 0x43a2:qǐ # 䎢 0x43a3:sì,xìn # 䎣 0x43a4:chú,jú # 䎤 0x43a6:yǎn # 䎦 0x43a7:bàng,póu # 䎧 0x43a8:àn,yè # 䎨 0x43aa:nè # 䎪 0x43ab:chuàng,zǒng # 䎫 0x43ac:bēi,bà # 䎬 0x43ae:tì # 䎮 0x43af:hàn # 䎯 0x43b0:zuó # 䎰 0x43b1:bēi,bà # 䎱 0x43b2:zhé # 䎲 0x43b3:wà,yuè # 䎳 0x43b4:shèng # 䎴 0x43b5:bì # 䎵 0x43b6:èr # 䎶 0x43b7:zhù # 䎷 0x43b8:wù # 䎸 0x43b9:wén # 䎹 0x43ba:zhǐ,zhì # 䎺 0x43bb:zhǒu # 䎻 0x43bc:lù # 䎼 0x43bd:wén,wèn # 䎽 0x43be:gǔn # 䎾 0x43bf:qiú,xiòng # 䎿 0x43c0:là # 䏀 0x43c1:zǎi # 䏁 0x43c2:sǒu # 䏂 0x43c3:mián # 䏃 0x43c4:zhì # 䏄 0x43c5:qì # 䏅 0x43c6:cáo # 䏆 0x43c7:piào # 䏇 0x43c8:lián # 䏈 0x43ca:lóng # 䏊 0x43cb:sù # 䏋 0x43cc:qì,yì # 䏌 0x43cd:yuàn # 䏍 0x43ce:féng,hàn # 䏎 0x43d0:jué,zhuò # 䏐 0x43d1:dì,zhì # 䏑 0x43d2:piàn # 䏒 0x43d3:guǎn # 䏓 0x43d4:niǔ # 䏔 0x43d5:rěn,rùn # 䏕 0x43d6:zhèn # 䏖 0x43d7:gài,kuì # 䏗 0x43d8:pǐ,pì # 䏘 0x43d9:tǎn # 䏙 0x43da:chǎo,miǎo # 䏚 0x43db:chǔn # 䏛 0x43dd:chún,zhuǎn # 䏝 0x43de:mò # 䏞 0x43df:biè,bié # 䏟 0x43e0:qì # 䏠 0x43e1:shì # 䏡 0x43e2:bǐ # 䏢 0x43e3:jué,qù,qū # 䏣 0x43e4:sì # 䏤 0x43e6:huá,tián,wǎn # 䏦 0x43e7:ná # 䏧 0x43e8:huǐ # 䏨 0x43ea:èr # 䏪 0x43ec:móu # 䏬 0x43ee:xí,xié # 䏮 0x43ef:zhì # 䏯 0x43f0:rěn,chǔn # 䏰 0x43f1:jú # 䏱 0x43f2:dié # 䏲 0x43f3:zhè # 䏳 0x43f4:shào,shè # 䏴 0x43f5:měng # 䏵 0x43f6:bì # 䏶 0x43f7:hàn # 䏷 0x43f8:yú # 䏸 0x43f9:xiàn # 䏹 0x43fb:néng # 䏻 0x43fc:cán # 䏼 0x43fd:bù # 䏽 0x43ff:qǐ # 䏿 0x4400:jì # 䐀 0x4401:niǎo,zhuó # 䐁 0x4402:lù # 䐂 0x4403:jiǒng # 䐃 0x4404:hàn,liǎn,xiàn # 䐄 0x4405:yí # 䐅 0x4406:cǎi,cài # 䐆 0x4407:chún # 䐇 0x4408:zhí # 䐈 0x4409:zì # 䐉 0x440a:dá,hún,hùn # 䐊 0x440c:tiǎn,zhòu # 䐌 0x440d:zhòu # 䐍 0x440f:chǔn # 䐏 0x4411:zhé # 䐑 0x4413:róu,rù # 䐓 0x4414:bìn # 䐔 0x4415:jí # 䐕 0x4416:yí # 䐖 0x4417:dǔ # 䐗 0x4418:jué # 䐘 0x4419:gé,yì # 䐙 0x441a:jí,jì # 䐚 0x441d:suǒ,suò # 䐝 0x441e:ruò # 䐞 0x441f:xiàng # 䐟 0x4420:huǎng # 䐠 0x4421:qí # 䐡 0x4422:zhù # 䐢 0x4423:cuò,sǔn # 䐣 0x4424:chí,cuó,qì,zhàn # 䐤 0x4425:wěng # 䐥 0x4427:kào # 䐧 0x4428:gǔ # 䐨 0x4429:kǎi # 䐩 0x442a:fàn,juǎn # 䐪 0x442c:cáo # 䐬 0x442d:zhì # 䐭 0x442e:chǎn # 䐮 0x442f:léi # 䐯 0x4432:zhé # 䐲 0x4433:yú # 䐳 0x4434:guì # 䐴 0x4435:huáng # 䐵 0x4436:jǐn # 䐶 0x4438:guó,huò # 䐸 0x4439:sào,sōu # 䐹 0x443a:tàn # 䐺 0x443c:xì # 䐼 0x443d:mán # 䐽 0x443e:duó # 䐾 0x443f:áo,ǎo # 䐿 0x4440:pì # 䑀 0x4441:wù # 䑁 0x4442:ǎi,xì # 䑂 0x4443:méng # 䑃 0x4444:pì,yì # 䑄 0x4445:méng # 䑅 0x4446:yǎng # 䑆 0x4447:zhì # 䑇 0x4448:bó # 䑈 0x4449:yíng # 䑉 0x444a:wéi,wèi # 䑊 0x444b:náo,rǎng # 䑋 0x444c:lán # 䑌 0x444d:yàn,yǐng # 䑍 0x444e:chǎn # 䑎 0x444f:quán # 䑏 0x4450:zhěn # 䑐 0x4451:pú # 䑑 0x4453:tái,tǎi # 䑓 0x4454:fèi # 䑔 0x4455:shǔ # 䑕 0x4457:dàng # 䑗 0x4458:chá,cuó # 䑘 0x4459:rán # 䑙 0x445a:tián # 䑚 0x445b:chǐ,shì,yì # 䑛 0x445c:tà # 䑜 0x445d:jiǎ # 䑝 0x445e:shùn # 䑞 0x445f:huáng # 䑟 0x4460:liǎo # 䑠 0x4464:jìn,jìng # 䑤 0x4465:è,sà # 䑥 0x4467:fú # 䑧 0x4468:duò # 䑨 0x446a:è # 䑪 0x446c:yào # 䑬 0x446d:dì,zhì # 䑭 0x446f:dì # 䑯 0x4470:bù # 䑰 0x4471:mán,wǎn # 䑱 0x4472:chè,zhái,zhào # 䑲 0x4473:lún # 䑳 0x4474:qí # 䑴 0x4475:mù # 䑵 0x4476:cán,qiàn # 䑶 0x447b:yóu # 䑻 0x447d:dá,tà # 䑽 0x447f:sù # 䑿 0x4480:fú # 䒀 0x4481:jì,xí,xiào,yà # 䒁 0x4482:jiǎng,xiǎng # 䒂 0x4483:zào # 䒃 0x4484:bó,fù # 䒄 0x4485:téng # 䒅 0x4486:chè # 䒆 0x4487:fù # 䒇 0x4488:bǔ,fèi # 䒈 0x4489:wǔ # 䒉 0x448b:yǎng # 䒋 0x448c:mìng # 䒌 0x448d:pǎng # 䒍 0x448e:mǎng # 䒎 0x4490:méng # 䒐 0x4491:cǎo # 䒑 0x4492:tiáo,yǎo,yóu # 䒒 0x4493:kǎi # 䒓 0x4494:bài # 䒔 0x4495:xiǎo # 䒕 0x4496:xìn # 䒖 0x4497:qì # 䒗 0x449a:shǎo # 䒚 0x449b:héng,huàn # 䒛 0x449c:niú # 䒜 0x449d:xiáo # 䒝 0x449e:chén # 䒞 0x44a0:fēng,xiá # 䒠 0x44a1:yǐn # 䒡 0x44a2:áng,yìng # 䒢 0x44a3:rǎn # 䒣 0x44a4:rì # 䒤 0x44a5:fà,liǔ,mán # 䒥 0x44a6:fàn # 䒦 0x44a7:qù # 䒧 0x44a8:shǐ # 䒨 0x44a9:hé,xiá # 䒩 0x44aa:biàn # 䒪 0x44ab:dài # 䒫 0x44ac:mò # 䒬 0x44ad:děng # 䒭 0x44b2:chà # 䒲 0x44b3:duǒ # 䒳 0x44b4:yǒu # 䒴 0x44b5:hào # 䒵 0x44b8:xián,xuè,yuè # 䒸 0x44b9:lèi # 䒹 0x44ba:jǐn # 䒺 0x44bb:qǐ # 䒻 0x44bd:méi,wǎng # 䒽 0x44c2:yán # 䓂 0x44c3:yì # 䓃 0x44c4:yín # 䓄 0x44c5:qí # 䓅 0x44c6:zhé # 䓆 0x44c7:xì # 䓇 0x44c8:yì # 䓈 0x44c9:yé # 䓉 0x44ca:è,wú,yú # 䓊 0x44cc:zhì # 䓌 0x44cd:hǎn # 䓍 0x44ce:chuò # 䓎 0x44d0:chún # 䓐 0x44d1:bǐng,píng # 䓑 0x44d2:kuǎi # 䓒 0x44d3:chóu # 䓓 0x44d5:tuǒ,wěi # 䓕 0x44d6:qióng # 䓖 0x44d8:jiù # 䓘 0x44da:cú # 䓚 0x44db:fǔ,gǔ,qū # 䓛 0x44dd:méng,mèng # 䓝 0x44de:lì # 䓞 0x44df:liè # 䓟 0x44e0:tà # 䓠 0x44e2:gù # 䓢 0x44e3:liǎng # 䓣 0x44e5:là # 䓥 0x44e6:diǎn # 䓦 0x44e7:cì,jí # 䓧 0x44eb:jì,qí # 䓫 0x44ed:chà # 䓭 0x44ee:mào # 䓮 0x44ef:dú # 䓯 0x44f1:chái,zhài # 䓱 0x44f2:ruì,sà # 䓲 0x44f3:hěn # 䓳 0x44f4:ruán,ruǎn # 䓴 0x44f6:lài # 䓶 0x44f7:xìng # 䓷 0x44f9:yì # 䓹 0x44fa:měi,wèi # 䓺 0x44fc:hè,máng # 䓼 0x44fd:jì # 䓽 0x44ff:hǎn,hàn # 䓿 0x4501:lì # 䔁 0x4502:zǐ # 䔂 0x4503:zǔ # 䔃 0x4504:yáo # 䔄 0x4506:lí # 䔆 0x4507:qǐ,yǐ # 䔇 0x4508:gǎn,gòng,nǒu # 䔈 0x4509:lì # 䔉 0x450e:sù # 䔎 0x450f:chòu # 䔏 0x4511:xié,yé # 䔑 0x4512:bèi # 䔒 0x4513:xǔ # 䔓 0x4514:jìng,qiǎn,qiú,yǐng # 䔔 0x4515:pú # 䔕 0x4516:líng # 䔖 0x4517:xiáng # 䔗 0x4518:zuò # 䔘 0x4519:diào # 䔙 0x451a:chún # 䔚 0x451b:qǐng # 䔛 0x451c:nán # 䔜 0x451e:lǜ # 䔞 0x451f:chí,chǐ,yí # 䔟 0x4520:shǎo # 䔠 0x4521:yú # 䔡 0x4522:huá,huà # 䔢 0x4523:lí # 䔣 0x4527:lí,lì # 䔧 0x452a:duì,shuǎng # 䔪 0x452c:yì # 䔬 0x452d:nìng,zhǒu # 䔭 0x452f:hú,huà,kù # 䔯 0x4530:fú,fù # 䔰 0x4532:chéng,zhuó # 䔲 0x4533:nǎn,rán # 䔳 0x4534:cè,cuì # 䔴 0x4536:tí # 䔶 0x4537:qín # 䔷 0x4538:biǎo # 䔸 0x4539:suì # 䔹 0x453a:wéi # 䔺 0x453c:sè # 䔼 0x453d:ài # 䔽 0x453e:è,qì,zè # 䔾 0x453f:jiè,zǔn # 䔿 0x4540:kuǎn # 䕀 0x4541:fěi # 䕁 0x4543:yìn # 䕃 0x4545:sǎo # 䕅 0x4546:dòu # 䕆 0x4547:huì # 䕇 0x4548:xiè # 䕈 0x4549:zé # 䕉 0x454a:tán # 䕊 0x454b:chǎng,táng # 䕋 0x454c:zhì # 䕌 0x454d:yì # 䕍 0x454e:fú # 䕎 0x454f:é # 䕏 0x4551:jùn # 䕑 0x4553:chá,chuì # 䕓 0x4554:xián # 䕔 0x4555:màn # 䕕 0x4557:bì,pèi # 䕗 0x4558:líng # 䕘 0x4559:jié # 䕙 0x455a:kuì # 䕚 0x455b:jiá # 䕛 0x455e:làng,liáo # 䕞 0x4560:fèi # 䕠 0x4561:lǘ # 䕡 0x4562:zhǎ # 䕢 0x4563:hé,kě,shé # 䕣 0x4565:nǐ,yí # 䕥 0x4566:yíng # 䕦 0x4567:xiào # 䕧 0x4568:téng # 䕨 0x4569:lǎo # 䕩 0x456a:zé # 䕪 0x456b:kuí # 䕫 0x456d:qián # 䕭 0x456e:jú # 䕮 0x456f:piáo # 䕯 0x4570:bàn,fán,fàn # 䕰 0x4571:dǒu,dòu,tóu # 䕱 0x4572:lǐn # 䕲 0x4573:mí # 䕳 0x4574:zhuó # 䕴 0x4575:xié,xiè # 䕵 0x4576:hù # 䕶 0x4577:mí # 䕷 0x4579:zá # 䕹 0x457a:cóng # 䕺 0x457b:gé,lì,lí # 䕻 0x457c:nán,nàn,rán # 䕼 0x457d:zhú # 䕽 0x457e:yán,yín # 䕾 0x457f:hàn # 䕿 0x4581:yì # 䖁 0x4582:luán # 䖂 0x4583:yuè # 䖃 0x4584:rán # 䖄 0x4585:líng # 䖅 0x4586:niàng # 䖆 0x4587:yù # 䖇 0x4588:nüè # 䖈 0x458a:yí,yì # 䖊 0x458b:nüè # 䖋 0x458c:qín,yá,yì # 䖌 0x458d:qián # 䖍 0x458e:xiá # 䖎 0x458f:chǔ # 䖏 0x4590:jìn,yín # 䖐 0x4591:mì # 䖑 0x4593:nà # 䖓 0x4594:hàn,kǎn # 䖔 0x4595:zǔ # 䖕 0x4596:xiá # 䖖 0x4597:yán,yàn # 䖗 0x4598:tú # 䖘 0x459b:suǒ # 䖛 0x459c:yín,yìn # 䖜 0x459d:chóng # 䖝 0x459e:zhǒu # 䖞 0x459f:mǎng,méng # 䖟 0x45a0:yuán # 䖠 0x45a1:nǜ # 䖡 0x45a2:miáo # 䖢 0x45a3:zǎo # 䖣 0x45a4:wǎn,yuán # 䖤 0x45a5:máo # 䖥 0x45a7:nà # 䖧 0x45a8:shí # 䖨 0x45a9:bì,pì # 䖩 0x45aa:cí # 䖪 0x45ab:bàng # 䖫 0x45ad:juàn # 䖭 0x45ae:xiǎng # 䖮 0x45af:kuí,wā # 䖯 0x45b0:pài # 䖰 0x45b2:xún # 䖲 0x45b3:zhà # 䖳 0x45b4:yáo # 䖴 0x45b8:é # 䖸 0x45b9:yáng # 䖹 0x45ba:tiáo,zhào # 䖺 0x45bb:yóu # 䖻 0x45bc:jué,xuè # 䖼 0x45bd:lí # 䖽 0x45bf:lí # 䖿 0x45c1:jì,qī # 䗁 0x45c2:hǔ # 䗂 0x45c3:zhàn # 䗃 0x45c4:fǔ,pì # 䗄 0x45c5:cháng # 䗅 0x45c6:guǎn,wěi # 䗆 0x45c7:jú,qú # 䗇 0x45c8:méng # 䗈 0x45ca:chéng,tàn # 䗊 0x45cb:móu # 䗋 0x45cd:lǐ # 䗍 0x45d1:yì # 䗑 0x45d2:bìng # 䗒 0x45d4:hóu # 䗔 0x45d5:wǎn # 䗕 0x45d6:dì # 䗖 0x45d8:gé,kè # 䗘 0x45d9:hán # 䗙 0x45da:bó # 䗚 0x45dc:liú # 䗜 0x45dd:cán # 䗝 0x45de:cán,chěn,shǎn,yǐn,zàn,zhàn # 䗞 0x45df:yì # 䗟 0x45e0:xuán # 䗠 0x45e1:yán # 䗡 0x45e2:zǎo # 䗢 0x45e3:gǎo,hàn # 䗣 0x45e4:yóng # 䗤 0x45e8:yú # 䗨 0x45ea:zhè # 䗪 0x45eb:má # 䗫 0x45ee:shuǎng # 䗮 0x45ef:jìn # 䗯 0x45f0:guàn # 䗰 0x45f1:pú # 䗱 0x45f2:lìn # 䗲 0x45f4:tíng # 䗴 0x45f6:là,lì # 䗶 0x45f7:yì # 䗷 0x45f9:cì # 䗹 0x45fa:yǎn # 䗺 0x45fb:jié # 䗻 0x45fd:wèi # 䗽 0x45fe:xiǎn # 䗾 0x45ff:níng # 䗿 0x4600:fù # 䘀 0x4601:gé,jié,kě # 䘁 0x4603:mò # 䘃 0x4604:fù,zhù # 䘄 0x4605:nái,nài,něng # 䘅 0x4606:xiǎn # 䘆 0x4607:wén,wèn # 䘇 0x4608:lì # 䘈 0x4609:cán # 䘉 0x460a:miè # 䘊 0x460c:nì # 䘌 0x460d:chài # 䘍 0x460f:xù # 䘏 0x4610:nǜ # 䘐 0x4611:mài,mò # 䘑 0x4613:kàn,kào # 䘓 0x4615:háng # 䘕 0x4618:yù # 䘘 0x4619:wèi # 䘙 0x461a:zú # 䘚 0x461d:yì # 䘝 0x4620:fú,pò # 䘠 0x4621:bǐ # 䘡 0x4622:zhǔ # 䘢 0x4623:zǐ # 䘣 0x4624:shù # 䘤 0x4625:xiá,jiá # 䘥 0x4626:ní,nǐ # 䘦 0x4628:jiǎo # 䘨 0x4629:xuàn,xún # 䘩 0x462b:nòu,rú # 䘫 0x462c:róng # 䘬 0x462d:dié,zhì # 䘭 0x462e:sà,sàng,xì # 䘮 0x4631:yù # 䘱 0x4635:lù # 䘵 0x4636:hàn,yǎn # 䘶 0x4638:yì # 䘸 0x4639:zuì # 䘹 0x463a:zhàn # 䘺 0x463b:sù,yù # 䘻 0x463c:wǎn # 䘼 0x463d:ní,nǐ,nì # 䘽 0x463e:guǎn # 䘾 0x463f:jué # 䘿 0x4640:běng # 䙀 0x4641:cán # 䙁 0x4643:duò,kuò,pán,ruán # 䙃 0x4644:qì,zhǎ # 䙄 0x4645:yào # 䙅 0x4646:guì,kuì # 䙆 0x4647:nuǎn,ruán # 䙇 0x4648:hóu # 䙈 0x4649:xún,zǎn # 䙉 0x464a:xiè # 䙊 0x464c:huì,kuì # 䙌 0x464e:xié # 䙎 0x464f:bó # 䙏 0x4650:kè # 䙐 0x4652:xù # 䙒 0x4653:bǎi # 䙓 0x4655:chù,zǒng # 䙕 0x4657:tì # 䙗 0x4658:chǔ,zú # 䙘 0x4659:chí # 䙙 0x465a:niǎo # 䙚 0x465b:guàn,gǔn # 䙛 0x465c:féng # 䙜 0x465d:xiè,dié # 䙝 0x465f:duò,wéi # 䙟 0x4660:jué,wò # 䙠 0x4661:huì,kuì # 䙡 0x4662:zèng # 䙢 0x4663:sà # 䙣 0x4664:duǒ,duò # 䙤 0x4665:líng # 䙥 0x4666:méng # 䙦 0x4668:guǒ,luǒ # 䙨 0x4669:méng # 䙩 0x466a:lóng,màng,pàn # 䙪 0x466c:yìng # 䙬 0x466e:guàn # 䙮 0x466f:cù,zhuó # 䙯 0x4670:lí # 䙰 0x4671:dú,shǔ # 䙱 0x4673:è # 䙳 0x4677:dé,zhé # 䙷 0x4678:dé,de # 䙸 0x4679:jiǎng,nǎo,xiàn,xiǎng # 䙹 0x467a:lián,liǎn,qiǎn # 䙺 0x467c:shào # 䙼 0x467d:xì,xié # 䙽 0x467f:wèi # 䙿 0x4682:hè,xì # 䚂 0x4683:yóu # 䚃 0x4684:lù # 䚄 0x4685:lái,lài # 䚅 0x4686:ǒu,yǎo,yǐng # 䚆 0x4687:shěng,zhì # 䚇 0x4688:juàn,wù,zhuàn # 䚈 0x4689:qì,xì # 䚉 0x468b:yùn # 䚋 0x468d:qì # 䚍 0x468f:lèng,lì,lìn # 䚏 0x4690:jí # 䚐 0x4691:mái # 䚑 0x4692:chuáng,zhuàng # 䚒 0x4693:niǎn,shěn # 䚓 0x4695:lì,luán # 䚕 0x4696:líng # 䚖 0x4698:chén,chéng # 䚘 0x469a:xiǎn # 䚚 0x469b:hú # 䚛 0x469d:zú # 䚝 0x469e:dǎi # 䚞 0x469f:dǎi # 䚟 0x46a0:hùn # 䚠 0x46a2:chè # 䚢 0x46a3:tí,tì # 䚣 0x46a5:nuò # 䚥 0x46a6:zhì # 䚦 0x46a7:liú # 䚧 0x46a8:fèi # 䚨 0x46a9:jiǎo,jiào # 䚩 0x46ab:áo,xí # 䚫 0x46ac:lín # 䚬 0x46ae:réng # 䚮 0x46af:tǎo,zhèn # 䚯 0x46b0:pǐ # 䚰 0x46b1:xìn # 䚱 0x46b2:shàn # 䚲 0x46b3:xiè,zhì # 䚳 0x46b4:wà # 䚴 0x46b5:tǒu # 䚵 0x46b7:xì,yǐ,yì # 䚷 0x46b8:xiè # 䚸 0x46b9:pǐ # 䚹 0x46ba:yáo # 䚺 0x46bb:yáo,yóu # 䚻 0x46bc:nǜ # 䚼 0x46bd:hào # 䚽 0x46be:nín,rén # 䚾 0x46bf:yìn # 䚿 0x46c0:fǎn # 䛀 0x46c1:nán # 䛁 0x46c2:chí,chǐ # 䛂 0x46c3:wàng # 䛃 0x46c4:yuǎn # 䛄 0x46c5:xiá # 䛅 0x46c6:zhòu # 䛆 0x46c7:yuǎn # 䛇 0x46c8:shì # 䛈 0x46c9:mì,miàn # 䛉 0x46cb:gé,jì # 䛋 0x46cc:páo,táo # 䛌 0x46cd:fèi # 䛍 0x46ce:hù,xuè,yù # 䛎 0x46cf:ní # 䛏 0x46d0:cí # 䛐 0x46d1:mì # 䛑 0x46d2:biàn # 䛒 0x46d4:ná # 䛔 0x46d5:yù # 䛕 0x46d6:è,yì # 䛖 0x46d7:zhǐ # 䛗 0x46d8:nín,rén # 䛘 0x46d9:xù # 䛙 0x46da:lüè # 䛚 0x46db:huì,qì # 䛛 0x46dc:xùn # 䛜 0x46dd:náo # 䛝 0x46de:hǎn,hàn # 䛞 0x46df:jiá # 䛟 0x46e0:dòu,xiáng # 䛠 0x46e1:huà # 䛡 0x46e4:cù # 䛤 0x46e5:xì # 䛥 0x46e6:sòng # 䛦 0x46e7:mí # 䛧 0x46e8:xìn # 䛨 0x46e9:wù # 䛩 0x46ea:qióng,wěi # 䛪 0x46eb:zhèng # 䛫 0x46ec:táo # 䛬 0x46ed:xìng # 䛭 0x46ee:jiù # 䛮 0x46ef:jù # 䛯 0x46f0:hún,hùn # 䛰 0x46f1:tí # 䛱 0x46f2:mán,màn # 䛲 0x46f3:jiǎn,yàn # 䛳 0x46f4:qǐ # 䛴 0x46f5:shòu # 䛵 0x46f6:lěi # 䛶 0x46f7:wǎn # 䛷 0x46f8:chè,shǎn # 䛸 0x46f9:càn # 䛹 0x46fa:jiè # 䛺 0x46fb:yòu # 䛻 0x46fc:huǐ # 䛼 0x46fd:zhǎ # 䛽 0x46fe:sù # 䛾 0x46ff:gé # 䛿 0x4700:nǎo # 䜀 0x4701:xì # 䜁 0x4704:chí # 䜄 0x4705:wéi # 䜅 0x4706:mò,nèi,shé,suì,zhé # 䜆 0x4707:gǔn,gùn # 䜇 0x470a:zāo,zào # 䜊 0x470b:huì # 䜋 0x470c:luán # 䜌 0x470d:liáo # 䜍 0x470e:láo,lào # 䜎 0x4711:qià,wù # 䜑 0x4712:ào # 䜒 0x4713:niè,shè # 䜓 0x4714:suí # 䜔 0x4715:mài # 䜕 0x4716:tàn # 䜖 0x4717:xìn # 䜗 0x4718:jǐng # 䜘 0x4719:án # 䜙 0x471a:tà # 䜚 0x471b:chán,chàn # 䜛 0x471c:wèi # 䜜 0x471d:tuǎn # 䜝 0x471e:jì # 䜞 0x471f:chén,chèn # 䜟 0x4720:chè,zhì # 䜠 0x4721:xù,xuè,yù # 䜡 0x4722:xiǎn # 䜢 0x4723:xī,xīn,yín # 䜣 0x4727:nǎo # 䜧 0x4729:yàn # 䜩 0x472a:qiú # 䜪 0x472b:hóng # 䜫 0x472c:sǒng,xiù # 䜬 0x472d:jùn # 䜭 0x472e:liáo # 䜮 0x472f:jú # 䜯 0x4731:mǎn # 䜱 0x4732:liè # 䜲 0x4734:chù,shì # 䜴 0x4735:chǐ,shì # 䜵 0x4736:xiáng # 䜶 0x4738:měi # 䜸 0x4739:shù # 䜹 0x473a:cè # 䜺 0x473b:chǐ,shì # 䜻 0x473c:gú # 䜼 0x473d:yú # 䜽 0x4740:liáo,liú # 䝀 0x4741:láo # 䝁 0x4742:shù # 䝂 0x4743:zhé # 䝃 0x4748:è # 䝈 0x474a:shà # 䝊 0x474b:zòng # 䝋 0x474c:jué,jùn # 䝌 0x474d:jùn # 䝍 0x474f:lóu,lǒu # 䝏 0x4750:wéi # 䝐 0x4752:zhù # 䝒 0x4753:là,liè # 䝓 0x4755:zhé # 䝕 0x4756:zhǎo # 䝖 0x4758:yì # 䝘 0x475a:ní # 䝚 0x475d:yǐ # 䝝 0x475e:hào # 䝞 0x475f:yà,yè # 䝟 0x4760:huán,yuán # 䝠 0x4761:màn # 䝡 0x4762:màn,méng # 䝢 0x4763:qú # 䝣 0x4764:lǎo,liáo # 䝤 0x4765:háo # 䝥 0x4767:mén,mín # 䝧 0x4768:xián # 䝨 0x4769:zhèn # 䝩 0x476a:shú,shǔ # 䝪 0x476b:zuó # 䝫 0x476c:zhù # 䝬 0x476d:gòu # 䝭 0x476e:xuàn # 䝮 0x476f:yì # 䝯 0x4770:tí,zhì # 䝰 0x4772:jìn # 䝲 0x4773:cán # 䝳 0x4775:bù # 䝵 0x4776:liáng # 䝶 0x4777:zhì # 䝷 0x4778:jì # 䝸 0x4779:wǎn,yuàn # 䝹 0x477a:guàn # 䝺 0x477c:qíng # 䝼 0x477d:ài # 䝽 0x477e:fù # 䝾 0x477f:guì # 䝿 0x4780:gòu,hòu,mǐn # 䞀 0x4781:xiàn,yàn,yǎng,yàng # 䞁 0x4782:ruǎn # 䞂 0x4783:zhì # 䞃 0x4784:biào # 䞄 0x4785:yí # 䞅 0x4786:suǒ # 䞆 0x4787:dié,zhì # 䞇 0x4788:guǐ,guì # 䞈 0x4789:shèng # 䞉 0x478a:xùn # 䞊 0x478b:chèn # 䞋 0x478c:shé # 䞌 0x478d:qíng # 䞍 0x4790:chǔn,shǔn # 䞐 0x4791:hóng # 䞑 0x4792:dòng # 䞒 0x4793:chēng # 䞓 0x4794:wěi # 䞔 0x4795:dié,nǎ,niè,rú,xiè,yú # 䞕 0x4796:shǔ # 䞖 0x4798:jí # 䞘 0x4799:zá # 䞙 0x479a:qí # 䞚 0x479c:fù # 䞜 0x479d:ǎo,yù # 䞝 0x479e:fú # 䞞 0x479f:pò # 䞟 0x47a1:tǎn # 䞡 0x47a2:zhà,zuó # 䞢 0x47a3:chě,chè,qiè # 䞣 0x47a4:qú # 䞤 0x47a5:yòu # 䞥 0x47a6:hé,jié # 䞦 0x47a7:hòu # 䞧 0x47a8:guǐ,kuǐ # 䞨 0x47a9:è,ruí # 䞩 0x47aa:jiàng # 䞪 0x47ab:yǔn # 䞫 0x47ac:tòu # 䞬 0x47ad:qiǔ,qūn # 䞭 0x47af:fù # 䞯 0x47b0:zuó # 䞰 0x47b1:hú # 䞱 0x47b3:bó,fèi # 䞳 0x47b5:juě # 䞵 0x47b6:dì,tì # 䞶 0x47b7:jué # 䞷 0x47b8:fù # 䞸 0x47b9:huáng # 䞹 0x47bb:yǒng # 䞻 0x47bc:chuǐ,cuàn,jiàn,mèi # 䞼 0x47bd:suǒ # 䞽 0x47be:chí # 䞾 0x47c2:mán # 䟂 0x47c3:cà,zàn # 䟃 0x47c4:qì,zuó # 䟄 0x47c5:jiàn,zàn # 䟅 0x47c6:bì,bó # 䟆 0x47c8:zhí # 䟈 0x47c9:zhú # 䟉 0x47ca:qú # 䟊 0x47cb:zhǎn,zhàn # 䟋 0x47cc:jí,jié # 䟌 0x47cd:dián # 䟍 0x47cf:lì # 䟏 0x47d0:lì # 䟐 0x47d1:lǎ,yuè # 䟑 0x47d2:quán # 䟒 0x47d4:fù # 䟔 0x47d5:chà # 䟕 0x47d6:tàng # 䟖 0x47d7:shì # 䟗 0x47d8:hàng # 䟘 0x47d9:qiè # 䟙 0x47da:qí # 䟚 0x47db:bó # 䟛 0x47dc:nà # 䟜 0x47dd:tòu # 䟝 0x47de:chú # 䟞 0x47df:cù # 䟟 0x47e0:yuè # 䟠 0x47e1:dì # 䟡 0x47e2:chén,jiàn,niǎn # 䟢 0x47e3:chù # 䟣 0x47e4:bì # 䟤 0x47e5:máng,méng # 䟥 0x47e6:bá,bó,yuán # 䟦 0x47e7:tián # 䟧 0x47e8:mín # 䟨 0x47e9:liě # 䟩 0x47ea:fěng # 䟪 0x47ec:qiù # 䟬 0x47ed:tiáo # 䟭 0x47ee:fú # 䟮 0x47ef:kuò # 䟯 0x47f0:jiǎn # 䟰 0x47f4:zhèn # 䟴 0x47f5:qiú # 䟵 0x47f6:cuò,zuò # 䟶 0x47f7:chì,qì # 䟷 0x47f8:kuí # 䟸 0x47f9:liè,lìn # 䟹 0x47fa:bǎng,bèi,pèi # 䟺 0x47fb:dù # 䟻 0x47fc:wǔ # 䟼 0x47fe:juě,zhuó # 䟾 0x47ff:lù # 䟿 0x4800:chǎng # 䠀 0x4802:chú,chǔ # 䠂 0x4803:liǎng # 䠃 0x4804:tiǎn # 䠄 0x4805:kǔn,tà # 䠅 0x4806:cháng # 䠆 0x4807:jué # 䠇 0x4808:tú # 䠈 0x4809:huà,huàn,huǐ # 䠉 0x480a:fèi # 䠊 0x480b:bǐ,bì,mà # 䠋 0x480d:qiá,xiā # 䠍 0x480e:wò # 䠎 0x480f:jì # 䠏 0x4810:qù # 䠐 0x4811:kuǐ # 䠑 0x4812:hú # 䠒 0x4813:cù,jiù,qù # 䠓 0x4814:suì # 䠔 0x4817:qiù # 䠗 0x4818:pì # 䠘 0x4819:bèi,páng,páo # 䠙 0x481a:wà # 䠚 0x481b:jiǎo,xiào,yáo # 䠛 0x481c:róng # 䠜 0x481e:cù,qí # 䠞 0x481f:dié,shè # 䠟 0x4820:chì # 䠠 0x4821:cuó # 䠡 0x4822:mèng # 䠢 0x4823:xuǎn,xuàn # 䠣 0x4824:duǒ,duò # 䠤 0x4825:bié # 䠥 0x4826:zhè,zhì # 䠦 0x4827:chú # 䠧 0x4828:chàn,mà # 䠨 0x4829:guì # 䠩 0x482a:duàn # 䠪 0x482b:zòu # 䠫 0x482c:dèng # 䠬 0x482d:lái,lài # 䠭 0x482e:téng # 䠮 0x482f:yuè # 䠯 0x4830:quán # 䠰 0x4831:shǔ,zhú # 䠱 0x4832:líng # 䠲 0x4834:qǐn,yǐn,zhěn # 䠴 0x4835:fù # 䠵 0x4836:shè # 䠶 0x4837:tiǎo # 䠷 0x4839:hái # 䠹 0x483b:qióng # 䠻 0x483c:diào,shù,xuè,zhú # 䠼 0x483d:hái # 䠽 0x483e:shǎn,shàn # 䠾 0x483f:wài # 䠿 0x4840:zhǎn # 䡀 0x4841:lǒng # 䡁 0x4842:jiù # 䡂 0x4843:lì # 䡃 0x4845:mǐn,xiǎn,xún,zhèn,zuǎn,chūn # 䡅 0x4846:róng,rǒng # 䡆 0x4847:yuè # 䡇 0x4848:jué # 䡈 0x4849:kǎng # 䡉 0x484a:fán,fǎn,pèi # 䡊 0x484b:qí # 䡋 0x484c:hóng # 䡌 0x484d:fú,fǔ # 䡍 0x484e:lú # 䡎 0x484f:hóng # 䡏 0x4850:tuó # 䡐 0x4851:mín # 䡑 0x4852:tián # 䡒 0x4853:juàn # 䡓 0x4854:qǐ # 䡔 0x4855:zhěng # 䡕 0x4856:jìng # 䡖 0x4857:gǒng # 䡗 0x4858:tián # 䡘 0x4859:láng # 䡙 0x485a:mào # 䡚 0x485b:yìn # 䡛 0x485c:lù # 䡜 0x485d:yǔn,yuān # 䡝 0x485e:jú # 䡞 0x485f:pì # 䡟 0x4861:xié # 䡡 0x4862:biàn # 䡢 0x4865:róng # 䡥 0x4866:sǎng # 䡦 0x4867:wǔ # 䡧 0x4868:chà,chái,yín # 䡨 0x4869:gǔ,hòu,tǒu,zhěn,kēng # 䡩 0x486a:chán,shàn # 䡪 0x486b:péng # 䡫 0x486c:màn # 䡬 0x486f:shuàng,zǒng # 䡯 0x4870:kěng,kēng # 䡰 0x4871:zhuǎn # 䡱 0x4872:chán # 䡲 0x4874:chuáng,chōng # 䡴 0x4875:suì # 䡵 0x4876:bèi,pì # 䡶 0x4877:kài # 䡷 0x4879:zhì # 䡹 0x487a:wèi # 䡺 0x487b:mín # 䡻 0x487c:líng # 䡼 0x487e:nèi,niè # 䡾 0x487f:líng # 䡿 0x4880:qì # 䢀 0x4881:yuè # 䢁 0x4883:yì # 䢃 0x4884:xǐ,xǐ # 䢄 0x4885:chén # 䢅 0x4887:rǒng,rǒu # 䢇 0x4888:chén,qín # 䢈 0x4889:nóng # 䢉 0x488a:yóu # 䢊 0x488b:jì # 䢋 0x488c:bó # 䢌 0x488d:fǎng,fèn # 䢍 0x4890:cú # 䢐 0x4891:dǐ # 䢑 0x4893:yú # 䢓 0x4894:gé,hé,jiá # 䢔 0x4895:xù # 䢕 0x4896:yù # 䢖 0x4897:hé,qǔ # 䢗 0x4899:bài # 䢙 0x489a:gòng,háng # 䢚 0x489b:jiǒng # 䢛 0x489d:yà # 䢝 0x489e:nù,shù # 䢞 0x489f:yóu # 䢟 0x48a0:sòng # 䢠 0x48a1:xiè # 䢡 0x48a2:càng # 䢢 0x48a3:yáo # 䢣 0x48a4:shù # 䢤 0x48a5:yán,yàn # 䢥 0x48a6:shuài # 䢦 0x48a7:liào,lǐn,què # 䢧 0x48a9:yù # 䢩 0x48aa:bó,cuì,jiǎo,nǔ,qián # 䢪 0x48ab:suí # 䢫 0x48ad:yàn # 䢭 0x48ae:lèi # 䢮 0x48af:lín # 䢯 0x48b0:tái,tì # 䢰 0x48b1:dú,zhà # 䢱 0x48b2:yuè # 䢲 0x48b3:jǐ,jì # 䢳 0x48b5:yún # 䢵 0x48b9:jǔ # 䢹 0x48bb:chén,jìn,tán # 䢻 0x48bd:xiàng # 䢽 0x48be:xiǎn # 䢾 0x48c0:guǐ,wéi # 䣀 0x48c1:yǔ # 䣁 0x48c2:lěi,lèi # 䣂 0x48c4:tú # 䣄 0x48c5:chén # 䣅 0x48c6:xíng # 䣆 0x48c7:qiú # 䣇 0x48c8:hàng,liáo,xiàng # 䣈 0x48ca:dǎng # 䣊 0x48cb:cǎi # 䣋 0x48cc:dǐ # 䣌 0x48cd:yǎn # 䣍 0x48d1:chán # 䣑 0x48d3:lí # 䣓 0x48d4:suǒ,suò # 䣔 0x48d5:mǎ,mà # 䣕 0x48d6:mǎ # 䣖 0x48d8:táng # 䣘 0x48d9:péi # 䣙 0x48da:lóu,lú # 䣚 0x48dc:cuó # 䣜 0x48dd:tú # 䣝 0x48de:è # 䣞 0x48df:cán # 䣟 0x48e0:jié,tì # 䣠 0x48e1:tí,yí # 䣡 0x48e2:jí # 䣢 0x48e3:dǎng,dào # 䣣 0x48e4:jiào,jué # 䣤 0x48e5:bǐ,mì # 䣥 0x48e6:lèi # 䣦 0x48e7:yì # 䣧 0x48e8:chún # 䣨 0x48e9:chún # 䣩 0x48ea:pò # 䣪 0x48eb:lí # 䣫 0x48ec:zǎi # 䣬 0x48ed:tài # 䣭 0x48ee:pò # 䣮 0x48ef:tiǎn # 䣯 0x48f0:jù,yuàn # 䣰 0x48f1:xù,yì # 䣱 0x48f2:fàn # 䣲 0x48f4:xù # 䣴 0x48f5:èr # 䣵 0x48f6:huó,tián # 䣶 0x48f8:rǎn # 䣸 0x48f9:fá # 䣹 0x48fc:liáng # 䣼 0x48fd:tǐ # 䣽 0x48fe:mì # 䣾 0x4901:cén,chè,shè,yín # 䤁 0x4902:méi # 䤂 0x4903:yìn # 䤃 0x4904:miǎn,zhuàn # 䤄 0x4905:tú # 䤅 0x4906:kuí # 䤆 0x4909:mì,míng,mò,rú # 䤉 0x490a:róng # 䤊 0x490b:guó,yù # 䤋 0x490d:mí # 䤍 0x490e:jú # 䤎 0x490f:pǐ # 䤏 0x4910:jǐn # 䤐 0x4911:wàng # 䤑 0x4912:jǐ,jì # 䤒 0x4913:méng # 䤓 0x4914:jiàn,niú,xiàng # 䤔 0x4915:xuè # 䤕 0x4916:bào # 䤖 0x4917:gǎn # 䤗 0x4918:chǎn,qiǎn # 䤘 0x4919:lì # 䤙 0x491a:lǐ,lüè # 䤚 0x491b:qiú # 䤛 0x491c:dùn # 䤜 0x491d:yìng # 䤝 0x491e:yǔn # 䤞 0x491f:chén # 䤟 0x4920:jī,zhǐ # 䤠 0x4921:rǎn # 䤡 0x4923:lüè # 䤣 0x4925:guǐ # 䤥 0x4926:yuè # 䤦 0x4927:huì # 䤧 0x4928:pì # 䤨 0x4929:chá # 䤩 0x492a:duǒ # 䤪 0x492b:chán # 䤫 0x492d:kuàn,shì,suì,yí # 䤭 0x492e:shè # 䤮 0x492f:xíng # 䤯 0x4930:wěng,yíng # 䤰 0x4931:shì # 䤱 0x4932:chì # 䤲 0x4933:yè # 䤳 0x4934:hán # 䤴 0x4935:fèi # 䤵 0x4936:yè # 䤶 0x4937:yán,yǎn # 䤷 0x4938:zuàn # 䤸 0x493a:yǐn # 䤺 0x493b:duò # 䤻 0x493c:xiàn # 䤼 0x493f:qiè # 䤿 0x4940:chǎn # 䥀 0x4941:hán # 䥁 0x4942:mèng # 䥂 0x4943:yuè # 䥃 0x4944:cù,zǎn,zàn # 䥄 0x4945:qiàn,qín # 䥅 0x4946:jǐn,qín,ròu,wèi # 䥆 0x4947:shàn # 䥇 0x4948:mǔ # 䥈 0x494c:zhèng # 䥌 0x494d:zhì # 䥍 0x494e:chún # 䥎 0x494f:yǔ # 䥏 0x4950:móu # 䥐 0x4951:wàn # 䥑 0x4952:jiàng # 䥒 0x4954:sù # 䥔 0x4955:piě # 䥕 0x4956:tián # 䥖 0x4957:kuǎn # 䥗 0x4958:cù,cuò # 䥘 0x4959:suì # 䥙 0x495b:jié # 䥛 0x495c:jiàn # 䥜 0x495d:áo,āo # 䥝 0x495e:jiǎo # 䥞 0x495f:yè # 䥟 0x4961:yè # 䥡 0x4962:lóng # 䥢 0x4963:záo # 䥣 0x4964:báo,fú # 䥤 0x4965:lián # 䥥 0x4967:huán,xuán # 䥧 0x4968:lǜ,lú # 䥨 0x4969:wéi # 䥩 0x496a:xiǎn # 䥪 0x496b:tiě # 䥫 0x496c:bó # 䥬 0x496d:zhèng # 䥭 0x496e:zhú # 䥮 0x496f:bà,bài,bēi # 䥯 0x4970:mèng # 䥰 0x4971:xiě # 䥱 0x4975:xiǎo # 䥵 0x4976:lì # 䥶 0x4977:zhá # 䥷 0x4978:mí # 䥸 0x497a:yé # 䥺 0x497e:xiě # 䥾 0x4982:shàn # 䦂 0x4985:shàn,zhǎn # 䦅 0x4986:jué # 䦆 0x4987:jì # 䦇 0x4988:fǎng,hǎn,jí,mǒu,zá,zuǒ # 䦈 0x498a:niǎo # 䦊 0x498b:áo # 䦋 0x498c:chù,pò,ruì # 䦌 0x498d:wù # 䦍 0x498e:guǎn # 䦎 0x498f:xiè # 䦏 0x4990:tǐng # 䦐 0x4991:xiè # 䦑 0x4992:dàng # 䦒 0x4994:tǎn # 䦔 0x4996:xiá,xié # 䦖 0x4997:xù # 䦗 0x4998:bì,xiǎn,xiàn # 䦘 0x4999:sì # 䦙 0x499a:huò,kuǎ,kuà # 䦚 0x499b:zhèng,zhì # 䦛 0x499c:wú,wù # 䦜 0x499e:rùn # 䦞 0x499f:chuài # 䦟 0x49a0:shǐ # 䦠 0x49a1:huán # 䦡 0x49a2:kuò # 䦢 0x49a3:fù # 䦣 0x49a4:chuài,wěn # 䦤 0x49a5:xián # 䦥 0x49a6:qín # 䦦 0x49a7:qié,xì,yǎn # 䦧 0x49a8:lán # 䦨 0x49aa:yà # 䦪 0x49ac:què # 䦬 0x49ae:chǔn # 䦮 0x49af:zhì # 䦯 0x49b1:kuǐ,wěi # 䦱 0x49b2:qiàn,yán # 䦲 0x49b3:hàng,xiàng # 䦳 0x49b4:yì # 䦴 0x49b5:nǐ # 䦵 0x49b6:zhèng # 䦶 0x49b7:chuài,wěn # 䦷 0x49b9:shí # 䦹 0x49bb:cì,zǐ # 䦻 0x49bc:jué # 䦼 0x49bd:xù # 䦽 0x49be:yǔn # 䦾 0x49c1:chù,xǔ # 䧁 0x49c2:dào,tiǎo,zhào # 䧂 0x49c3:diàn,tián # 䧃 0x49c4:gè # 䧄 0x49c5:tì,yà,yí # 䧅 0x49c6:hóng,kǒu,qióng # 䧆 0x49c7:nǐ,yǐ,yī # 䧇 0x49c9:lǐ # 䧉 0x49cb:xiǎn # 䧋 0x49cd:xì # 䧍 0x49ce:xuàn # 䧎 0x49d2:lái,lǎn # 䧒 0x49d4:mù,niàn # 䧔 0x49d5:chéng,yù # 䧕 0x49d6:jiàn # 䧖 0x49d7:bì # 䧗 0x49d8:qí,zhuàn # 䧘 0x49d9:líng # 䧙 0x49da:hào # 䧚 0x49db:bàng # 䧛 0x49dc:táng # 䧜 0x49dd:chī,zhì # 䧝 0x49de:fù,mà # 䧞 0x49df:xiàn,xuàn # 䧟 0x49e0:shuàn # 䧠 0x49e4:pú # 䧤 0x49e5:huì # 䧥 0x49e6:wéi,huī # 䧦 0x49e7:yǐ # 䧧 0x49e8:yè # 䧨 0x49ea:chè,zhé # 䧪 0x49eb:háo # 䧫 0x49ee:xiǎn,xiàn # 䧮 0x49ef:chán,zhàn # 䧯 0x49f0:hùn # 䧰 0x49f2:hàn # 䧲 0x49f3:cí,cǐ # 䧳 0x49f5:qí,shěn,zhèn # 䧵 0x49f6:kuí # 䧶 0x49f7:róu # 䧷 0x49fa:xióng # 䧺 0x49fc:hú # 䧼 0x49fd:cuǐ # 䧽 0x49ff:què # 䧿 0x4a00:dí,dì # 䨀 0x4a01:chè,wù,yù # 䨁 0x4a04:yàn,ān # 䨄 0x4a05:liáo # 䨅 0x4a06:bí,bì,xù # 䨆 0x4a0b:nüè # 䨋 0x4a0c:báo,bó # 䨌 0x4a0d:yǐng # 䨍 0x4a0e:hóng # 䨎 0x4a0f:cí # 䨏 0x4a10:qià,xiá # 䨐 0x4a11:tí # 䨑 0x4a12:yù # 䨒 0x4a13:léi,lèi # 䨓 0x4a14:báo # 䨔 0x4a16:jì # 䨖 0x4a17:fú # 䨗 0x4a18:xiàn # 䨘 0x4a19:cén,yà,yín # 䨙 0x4a1b:sè # 䨛 0x4a1e:yǔ,yù # 䨞 0x4a20:ǎi # 䨠 0x4a21:hán # 䨡 0x4a22:dàn,dí,gào,tán # 䨢 0x4a23:gé,gèng # 䨣 0x4a24:dí # 䨤 0x4a25:hù,huò # 䨥 0x4a26:páng # 䨦 0x4a29:líng # 䨩 0x4a2a:mái # 䨪 0x4a2b:mài,màn # 䨫 0x4a2c:lián # 䨬 0x4a2e:xuě # 䨮 0x4a2f:zhèn # 䨯 0x4a30:pò # 䨰 0x4a31:fù # 䨱 0x4a32:nóu # 䨲 0x4a33:xì # 䨳 0x4a34:duì,wèng # 䨴 0x4a35:dàn # 䨵 0x4a36:yǔn # 䨶 0x4a37:xiàn # 䨷 0x4a38:yǐn # 䨸 0x4a3a:duì # 䨺 0x4a3b:bèng # 䨻 0x4a3c:hù # 䨼 0x4a3d:fěi # 䨽 0x4a3e:fěi # 䨾 0x4a3f:qián,zá # 䨿 0x4a40:bèi # 䩀 0x4a43:shì # 䩃 0x4a44:tiǎn # 䩄 0x4a45:zhǎn # 䩅 0x4a46:jiǎn,zhǎn # 䩆 0x4a48:huì,wèi,xuě # 䩈 0x4a49:fǔ # 䩉 0x4a4a:wǎn,wò # 䩊 0x4a4b:mǒ # 䩋 0x4a4c:qiáo,jiāo # 䩌 0x4a4d:liǎo # 䩍 0x4a4f:miè # 䩏 0x4a50:gé,jí # 䩐 0x4a51:hóng # 䩑 0x4a52:yú # 䩒 0x4a53:qí # 䩓 0x4a54:duò # 䩔 0x4a55:áng # 䩕 0x4a57:bà # 䩗 0x4a58:dì # 䩘 0x4a59:xuàn # 䩙 0x4a5a:dì,diàn # 䩚 0x4a5b:bì # 䩛 0x4a5c:zhòu # 䩜 0x4a5d:páo # 䩝 0x4a5e:nián,tiǎn,tié,wěi # 䩞 0x4a5f:yí,tì # 䩟 0x4a61:jiá # 䩡 0x4a62:dá,zhì # 䩢 0x4a63:duǒ,tú,tuì # 䩣 0x4a64:xì,xié # 䩤 0x4a65:dàn # 䩥 0x4a66:tiáo,zuò # 䩦 0x4a67:xiè # 䩧 0x4a68:chàng # 䩨 0x4a69:yuǎn # 䩩 0x4a6a:guǎn # 䩪 0x4a6b:liǎng # 䩫 0x4a6c:běng,fěng # 䩬 0x4a6e:lù # 䩮 0x4a6f:jí # 䩯 0x4a70:xuàn # 䩰 0x4a71:shù # 䩱 0x4a73:shǔ,sù # 䩳 0x4a74:hú # 䩴 0x4a75:yùn # 䩵 0x4a76:chǎn,chěng # 䩶 0x4a78:róng,rǒng # 䩸 0x4a79:é # 䩹 0x4a7b:bà # 䩻 0x4a7c:féng # 䩼 0x4a7e:zhè # 䩾 0x4a7f:fén # 䩿 0x4a80:guǎn,ruǎn # 䪀 0x4a81:bǔ # 䪁 0x4a82:gé # 䪂 0x4a84:huáng # 䪄 0x4a85:dú # 䪅 0x4a86:tǐ # 䪆 0x4a87:bó # 䪇 0x4a88:qiǎn,qiàn # 䪈 0x4a89:là,liè # 䪉 0x4a8a:lóng # 䪊 0x4a8b:wèi # 䪋 0x4a8c:zhàn # 䪌 0x4a8d:lán,làn # 䪍 0x4a8f:nà,dā # 䪏 0x4a90:bì,pì # 䪐 0x4a91:tuó # 䪑 0x4a92:jiào,zhì,zhù # 䪒 0x4a94:bǔ # 䪔 0x4a95:jú # 䪕 0x4a96:pò # 䪖 0x4a97:xiá # 䪗 0x4a98:wěi # 䪘 0x4a99:fú,pò # 䪙 0x4a9a:hè,tà # 䪚 0x4a9b:fán # 䪛 0x4a9c:chàn # 䪜 0x4a9d:hù # 䪝 0x4a9e:zá # 䪞 0x4aa4:fán # 䪤 0x4aa5:xiè # 䪥 0x4aa6:hóng # 䪦 0x4aa7:chí # 䪧 0x4aa8:báo,qú # 䪨 0x4aa9:yín # 䪩 0x4aac:bó,pú # 䪬 0x4aad:ruǎn # 䪭 0x4aae:chǒu # 䪮 0x4aaf:yíng # 䪯 0x4ab1:gǎi # 䪱 0x4ab3:yǔn # 䪳 0x4ab4:zhěn # 䪴 0x4ab5:yǎ # 䪵 0x4ab7:hòu # 䪷 0x4ab8:mín # 䪸 0x4ab9:péi # 䪹 0x4aba:gé # 䪺 0x4abb:biàn # 䪻 0x4abd:hào # 䪽 0x4abe:mí,zhěn # 䪾 0x4abf:shěng,xìn # 䪿 0x4ac0:gěn # 䫀 0x4ac1:bì # 䫁 0x4ac2:duǒ # 䫂 0x4ac3:chún # 䫃 0x4ac4:chuà # 䫄 0x4ac5:sàn # 䫅 0x4ac6:chéng,zhèng # 䫆 0x4ac7:rán # 䫇 0x4ac8:zèn,cén # 䫈 0x4ac9:mào # 䫉 0x4aca:bó,péi # 䫊 0x4acb:tuí # 䫋 0x4acc:pǐ # 䫌 0x4acd:fǔ # 䫍 0x4ad0:lín # 䫐 0x4ad2:mén # 䫒 0x4ad3:wú # 䫓 0x4ad4:qì,qiè,xì # 䫔 0x4ad5:zhì # 䫕 0x4ad6:chěn,huǐ,nòu,shèn,tíng,yà,zhù # 䫖 0x4ad7:xiá,xià # 䫗 0x4ad8:hé # 䫘 0x4ad9:sǎng # 䫙 0x4adb:hóu # 䫛 0x4add:fǔ,fù # 䫝 0x4ade:ráo,qiāo # 䫞 0x4adf:hùn # 䫟 0x4ae0:péi,pī # 䫠 0x4ae1:qiàn,yán # 䫡 0x4ae3:xí # 䫣 0x4ae4:míng # 䫤 0x4ae5:kuǐ,wěi # 䫥 0x4ae6:gé,kài # 䫦 0x4ae8:ào # 䫨 0x4ae9:sǎn # 䫩 0x4aea:shuǎng # 䫪 0x4aeb:lóu,lòu # 䫫 0x4aec:zhěn # 䫬 0x4aed:huì # 䫭 0x4aee:cán,cǎn,tì # 䫮 0x4af0:lìn,lǐn # 䫰 0x4af1:ná,rú # 䫱 0x4af2:hàn,kǎn # 䫲 0x4af3:dú # 䫳 0x4af4:jìn # 䫴 0x4af5:mián # 䫵 0x4af6:fán # 䫶 0x4af7:è # 䫷 0x4af8:náo # 䫸 0x4af9:hóng # 䫹 0x4afa:hóng,hòu # 䫺 0x4afb:xué,yù # 䫻 0x4afc:xuè # 䫼 0x4afe:bī,bì # 䫾 0x4b00:yǒu # 䬀 0x4b01:yí # 䬁 0x4b02:xuè,yuè # 䬂 0x4b03:sà # 䬃 0x4b04:yù # 䬄 0x4b05:lì,liè,xié # 䬅 0x4b06:lì # 䬆 0x4b07:yuàn # 䬇 0x4b08:duì # 䬈 0x4b09:hào # 䬉 0x4b0a:qiè,shà # 䬊 0x4b0b:léng # 䬋 0x4b0e:guó # 䬎 0x4b0f:bù,fǒu # 䬏 0x4b10:wěi # 䬐 0x4b11:wèi # 䬑 0x4b13:àn,ǎng # 䬓 0x4b14:xù,yú # 䬔 0x4b15:shǎng # 䬕 0x4b16:héng # 䬖 0x4b17:yáng # 䬗 0x4b19:yáo # 䬙 0x4b1b:bì,yù # 䬛 0x4b1d:héng,hòng # 䬝 0x4b1e:táo # 䬞 0x4b1f:liú # 䬟 0x4b21:zhù # 䬡 0x4b23:qì # 䬣 0x4b24:cháo,zàn,zuò # 䬤 0x4b25:yì # 䬥 0x4b26:dòu # 䬦 0x4b27:yuán # 䬧 0x4b28:cù,jiù,zú # 䬨 0x4b2a:bó,fù # 䬪 0x4b2b:cǎn,tí # 䬫 0x4b2c:yǎng # 䬬 0x4b2e:yí # 䬮 0x4b2f:nián # 䬯 0x4b30:shào # 䬰 0x4b31:bèn # 䬱 0x4b33:bǎn # 䬳 0x4b34:mò # 䬴 0x4b35:ài # 䬵 0x4b36:èn # 䬶 0x4b37:shě # 䬷 0x4b39:zhì # 䬹 0x4b3a:yàng # 䬺 0x4b3b:jiàn,kǎn # 䬻 0x4b3c:yuàn # 䬼 0x4b3d:duì,shuì # 䬽 0x4b3e:tí # 䬾 0x4b3f:wěi,wèi # 䬿 0x4b40:xùn # 䭀 0x4b41:zhì # 䭁 0x4b42:yì # 䭂 0x4b43:rěn # 䭃 0x4b44:shì # 䭄 0x4b45:hú # 䭅 0x4b46:nè # 䭆 0x4b47:yì # 䭇 0x4b48:jiàn # 䭈 0x4b49:suǐ # 䭉 0x4b4a:yǐng # 䭊 0x4b4b:bǎo # 䭋 0x4b4c:hú # 䭌 0x4b4d:hú # 䭍 0x4b4e:xié,yè # 䭎 0x4b50:yàng # 䭐 0x4b51:lián,qiàn,xiàn # 䭑 0x4b53:èn,wèn # 䭓 0x4b55:jiàn,zǎn # 䭕 0x4b56:zhù # 䭖 0x4b57:yǐng # 䭗 0x4b58:yàn,yǐng # 䭘 0x4b59:jǐn # 䭙 0x4b5a:chuáng,nè # 䭚 0x4b5b:dàn # 䭛 0x4b5d:kuài # 䭝 0x4b5e:yì # 䭞 0x4b5f:yè # 䭟 0x4b60:jiǎn,qiàn # 䭠 0x4b61:èn,wèn # 䭡 0x4b62:níng # 䭢 0x4b63:cí # 䭣 0x4b64:qiǎn # 䭤 0x4b65:xuè,yàng,yào,zhòu # 䭥 0x4b66:bó # 䭦 0x4b67:mǐ # 䭧 0x4b68:shuì # 䭨 0x4b69:mì,mó # 䭩 0x4b6a:liáng # 䭪 0x4b6b:qǐ # 䭫 0x4b6c:qǐ # 䭬 0x4b6d:shǒu,shú,shù,tù # 䭭 0x4b6e:bì,fú # 䭮 0x4b6f:bó # 䭯 0x4b70:běng,bèng # 䭰 0x4b71:bié # 䭱 0x4b72:nǐ,yǐ # 䭲 0x4b73:wèi # 䭳 0x4b74:huán,yuàn # 䭴 0x4b75:fán # 䭵 0x4b76:qí # 䭶 0x4b77:liú,máo # 䭷 0x4b78:fù # 䭸 0x4b79:áng,àng # 䭹 0x4b7a:áng # 䭺 0x4b7c:qí # 䭼 0x4b7d:qún # 䭽 0x4b7e:tuó # 䭾 0x4b7f:yì # 䭿 0x4b80:bó # 䮀 0x4b81:pián # 䮁 0x4b82:bó # 䮂 0x4b84:xuán # 䮄 0x4b87:yù # 䮇 0x4b88:chí # 䮈 0x4b89:lú # 䮉 0x4b8a:yí # 䮊 0x4b8b:lì,liè # 䮋 0x4b8d:niǎo,xìng # 䮍 0x4b8e:xì # 䮎 0x4b8f:wú # 䮏 0x4b91:lèi # 䮑 0x4b93:zhào # 䮓 0x4b94:zuǐ,zuī # 䮔 0x4b95:chuò # 䮕 0x4b97:àn,niù,yàn # 䮗 0x4b98:ér,ní,pài,pó # 䮘 0x4b99:yù # 䮙 0x4b9a:lèng # 䮚 0x4b9b:fù # 䮛 0x4b9c:shà,zhá # 䮜 0x4b9d:huán,huǎn,hún # 䮝 0x4b9e:chù,chǔn # 䮞 0x4b9f:sǒu # 䮟 0x4ba1:bì # 䮡 0x4ba2:dié # 䮢 0x4ba4:dí,hè,hé # 䮤 0x4ba5:lì # 䮥 0x4ba7:hán,hàn # 䮧 0x4ba8:zǎi # 䮨 0x4ba9:gú,gǔ # 䮩 0x4baa:chéng # 䮪 0x4bab:lóu # 䮫 0x4bac:mò # 䮬 0x4bad:mì # 䮭 0x4bae:mài # 䮮 0x4baf:ào # 䮯 0x4bb0:zhé # 䮰 0x4bb1:zhú # 䮱 0x4bb2:huáng # 䮲 0x4bb3:fán # 䮳 0x4bb4:dèng # 䮴 0x4bb5:tóng,yǒng # 䮵 0x4bb7:dú # 䮷 0x4bb8:hú,mú,wò # 䮸 0x4bb9:wèi # 䮹 0x4bba:jì # 䮺 0x4bbb:chì,dǎo,dào,děi # 䮻 0x4bbc:lín # 䮼 0x4bbe:páng # 䮾 0x4bbf:jiǎn # 䮿 0x4bc0:niè # 䯀 0x4bc1:luó # 䯁 0x4bc2:jí,shēn # 䯂 0x4bc5:niè # 䯅 0x4bc6:yì # 䯆 0x4bc8:wán # 䯈 0x4bc9:yà,wā # 䯉 0x4bca:qià # 䯊 0x4bcb:bó # 䯋 0x4bcd:líng # 䯍 0x4bce:gàn # 䯎 0x4bcf:huó,guā # 䯏 0x4bd0:hái # 䯐 0x4bd2:héng # 䯒 0x4bd3:kuí # 䯓 0x4bd4:cén,zé # 䯔 0x4bd6:láng # 䯖 0x4bd7:bì # 䯗 0x4bd8:huàn # 䯘 0x4bd9:pò # 䯙 0x4bda:ǒu,yǎo # 䯚 0x4bdb:jiǎn,wàn # 䯛 0x4bdc:tì # 䯜 0x4bdd:suǐ # 䯝 0x4bdf:duì,xiá # 䯟 0x4be0:ǎo,ào # 䯠 0x4be1:jiǎn,jiàn,qiàn # 䯡 0x4be2:mó,mǒ # 䯢 0x4be3:guì,kuì # 䯣 0x4be4:kuài # 䯤 0x4be5:àn,qì # 䯥 0x4be6:mà # 䯦 0x4be7:qǐng # 䯧 0x4be8:fén,hè # 䯨 0x4bea:kǎo # 䯪 0x4beb:hào,shà # 䯫 0x4bec:duǒ # 䯬 0x4bee:nái # 䯮 0x4bf0:jiè # 䯰 0x4bf1:fù,pēi,pī # 䯱 0x4bf2:pá # 䯲 0x4bf4:cháng # 䯴 0x4bf5:niè # 䯵 0x4bf6:mán # 䯶 0x4bf8:cì # 䯸 0x4bfa:kuò # 䯺 0x4bfc:dí # 䯼 0x4bfd:fǔ,póu # 䯽 0x4bfe:tiáo # 䯾 0x4bff:zú,zuó # 䯿 0x4c00:wǒ # 䰀 0x4c01:fèi # 䰁 0x4c02:cài # 䰂 0x4c03:péng # 䰃 0x4c04:shì # 䰄 0x4c06:róu # 䰆 0x4c07:qí # 䰇 0x4c08:chǎ,cuó,cuǒ # 䰈 0x4c09:pán,pàn # 䰉 0x4c0a:bó # 䰊 0x4c0b:mán # 䰋 0x4c0c:zǒng # 䰌 0x4c0d:cì,qī,xiū # 䰍 0x4c0e:guì,huǐ,kuì # 䰎 0x4c0f:jì # 䰏 0x4c10:lán # 䰐 0x4c12:méng # 䰒 0x4c13:mián # 䰓 0x4c14:pán # 䰔 0x4c15:lú # 䰕 0x4c16:cuán # 䰖 0x4c18:liú # 䰘 0x4c19:yǐ # 䰙 0x4c1a:wén # 䰚 0x4c1b:lì # 䰛 0x4c1c:lì # 䰜 0x4c1d:zèng # 䰝 0x4c1e:zhǔ # 䰞 0x4c1f:hún # 䰟 0x4c20:shén,shēn # 䰠 0x4c21:chì # 䰡 0x4c22:xìng # 䰢 0x4c23:wǎng # 䰣 0x4c25:huò,jì,shè,yù # 䰥 0x4c26:pǐ,pì # 䰦 0x4c28:mèi # 䰨 0x4c29:chě,chǐ # 䰩 0x4c2a:mèi # 䰪 0x4c2b:cháo # 䰫 0x4c2c:jú # 䰬 0x4c2d:nòu,rú # 䰭 0x4c2f:nǐ,rán,yì # 䰯 0x4c30:rú # 䰰 0x4c31:líng # 䰱 0x4c32:yà # 䰲 0x4c34:qì,zhì # 䰴 0x4c37:bàng,bó # 䰷 0x4c39:zé # 䰹 0x4c3a:jiè # 䰺 0x4c3b:yú # 䰻 0x4c3c:xín,qín # 䰼 0x4c3d:bèi # 䰽 0x4c3e:bā # 䰾 0x4c3f:tuó # 䰿 0x4c41:qiáo # 䱁 0x4c42:yǒu # 䱂 0x4c43:dǐ,zhì # 䱃 0x4c44:jiè # 䱄 0x4c45:mò # 䱅 0x4c46:shéng # 䱆 0x4c47:shàn,táo # 䱇 0x4c48:qí,yì # 䱈 0x4c49:shàn # 䱉 0x4c4a:mǐ # 䱊 0x4c4b:dǎn,gǒng # 䱋 0x4c4c:yí # 䱌 0x4c4d:gèng # 䱍 0x4c4e:gèng # 䱎 0x4c4f:tǒu # 䱏 0x4c51:xué # 䱑 0x4c52:yì # 䱒 0x4c53:tíng # 䱓 0x4c54:tiáo # 䱔 0x4c55:móu # 䱕 0x4c56:liú,liǔ # 䱖 0x4c58:lí # 䱘 0x4c5a:lù # 䱚 0x4c5b:huò # 䱛 0x4c5c:cuò,què # 䱜 0x4c5d:bà,pái # 䱝 0x4c5e:liú,nài,wěi # 䱞 0x4c5f:jù # 䱟 0x4c60:zhàn # 䱠 0x4c61:jú # 䱡 0x4c63:zú # 䱣 0x4c64:xiàn # 䱤 0x4c65:zhì,jì # 䱥 0x4c68:zhì # 䱨 0x4c6b:là # 䱫 0x4c6d:gèng # 䱭 0x4c6e:é # 䱮 0x4c6f:mú # 䱯 0x4c70:zhòng # 䱰 0x4c71:dì,tí # 䱱 0x4c72:yán # 䱲 0x4c74:gèng # 䱴 0x4c76:láng # 䱶 0x4c77:yú # 䱷 0x4c79:nà,zhǎ # 䱹 0x4c7a:hái # 䱺 0x4c7b:huá # 䱻 0x4c7c:zhǎn # 䱼 0x4c7e:lóu,yú # 䱾 0x4c7f:chàn # 䱿 0x4c80:dié,suì,zhì,zòu # 䲀 0x4c81:wèi # 䲁 0x4c82:xuán # 䲂 0x4c83:zǎo # 䲃 0x4c84:mín,mǐn # 䲄 0x4c8a:tuǒ,duò # 䲊 0x4c8b:cén # 䲋 0x4c8c:kuǎn # 䲌 0x4c8d:téng # 䲍 0x4c8e:něi # 䲎 0x4c8f:láo # 䲏 0x4c90:lǔ # 䲐 0x4c91:yí # 䲑 0x4c92:xiè # 䲒 0x4c93:yǎn # 䲓 0x4c94:qíng,qìng,jīng # 䲔 0x4c95:pǔ,pù # 䲕 0x4c96:chóu # 䲖 0x4c97:xián # 䲗 0x4c98:guǎn,kàng,wéi # 䲘 0x4c99:jié # 䲙 0x4c9a:lài,làn # 䲚 0x4c9b:méng # 䲛 0x4c9c:yè # 䲜 0x4c9e:lì,luǒ # 䲞 0x4c9f:yìn # 䲟 0x4ca2:téng # 䲢 0x4ca3:yú # 䲣 0x4ca6:chá,dài,dì,tuǒ # 䲦 0x4ca7:dù,shuì # 䲧 0x4ca8:hóng # 䲨 0x4caa:xì # 䲪 0x4cac:qí # 䲬 0x4cae:yuán # 䲮 0x4caf:jí # 䲯 0x4cb0:yùn # 䲰 0x4cb1:fǎng # 䲱 0x4cb3:háng # 䲳 0x4cb4:zhèn # 䲴 0x4cb5:hù,què # 䲵 0x4cb8:jiè # 䲸 0x4cb9:péi # 䲹 0x4cba:gàn # 䲺 0x4cbb:xuán,yuán # 䲻 0x4cbd:dǎo,shí # 䲽 0x4cbe:qiǎo # 䲾 0x4cbf:cí # 䲿 0x4cc0:dié # 䳀 0x4cc1:bá,bǐn,bó,yuán # 䳁 0x4cc2:tiáo # 䳂 0x4cc3:wǎn # 䳃 0x4cc4:cí # 䳄 0x4cc5:zhǐ # 䳅 0x4cc6:bái # 䳆 0x4cc7:wǔ # 䳇 0x4cc8:bǎo # 䳈 0x4cc9:dōng,dàn # 䳉 0x4cca:bá # 䳊 0x4ccb:tóng,zhòng # 䳋 0x4cce:jiù # 䳎 0x4ccf:guì # 䳏 0x4cd0:cì # 䳐 0x4cd1:yǒu,yù # 䳑 0x4cd2:yuán # 䳒 0x4cd3:lǎo # 䳓 0x4cd4:jiù,jú # 䳔 0x4cd5:fóu # 䳕 0x4cd6:nèi,yè # 䳖 0x4cd7:é # 䳗 0x4cd8:é # 䳘 0x4cd9:xǐng # 䳙 0x4cda:hé,kǎn # 䳚 0x4cdb:yàn # 䳛 0x4cdc:tú # 䳜 0x4cdd:bù,diào,fǔ,pǒu # 䳝 0x4cde:běng # 䳞 0x4cdf:kòu,míng,mǒ # 䳟 0x4ce0:chuí,ruì,zhù # 䳠 0x4ce2:qí # 䳢 0x4ce3:yuán # 䳣 0x4ce7:hóu # 䳧 0x4ce8:huáng # 䳨 0x4cea:juàn,tuán # 䳪 0x4ceb:kuí # 䳫 0x4cec:è,yǎo,yì # 䳬 0x4ced:jí # 䳭 0x4cee:mò # 䳮 0x4cef:chóng,chǒng # 䳯 0x4cf0:bǎo # 䳰 0x4cf1:wù # 䳱 0x4cf2:zhèn # 䳲 0x4cf3:xù # 䳳 0x4cf4:dá,tà # 䳴 0x4cf5:chì # 䳵 0x4cf7:cóng # 䳷 0x4cf8:má,mái # 䳸 0x4cf9:kòu # 䳹 0x4cfa:yàn # 䳺 0x4cfb:cán,chán,dié,zhàn # 䳻 0x4cfd:hè # 䳽 0x4cff:lán,rán # 䳿 0x4d00:tóng # 䴀 0x4d01:yù # 䴁 0x4d02:hàng,xiàng # 䴂 0x4d03:náo # 䴃 0x4d04:lì,shùn # 䴄 0x4d05:fén # 䴅 0x4d06:pú # 䴆 0x4d07:líng # 䴇 0x4d08:ǎo # 䴈 0x4d09:xuán # 䴉 0x4d0a:yí # 䴊 0x4d0b:xuán # 䴋 0x4d0c:méng # 䴌 0x4d0e:lěi # 䴎 0x4d0f:yàn # 䴏 0x4d10:bǎo # 䴐 0x4d11:dié # 䴑 0x4d12:líng # 䴒 0x4d13:shī # 䴓 0x4d14:jiāo # 䴔 0x4d15:liè # 䴕 0x4d16:jīng # 䴖 0x4d17:jú # 䴗 0x4d18:tī # 䴘 0x4d19:pì # 䴙 0x4d1a:gǎng # 䴚 0x4d1b:jiǎo,tú,xì,xiào,yín # 䴛 0x4d1c:huái # 䴜 0x4d1d:bù,chuài # 䴝 0x4d1e:dí # 䴞 0x4d1f:huán,huàn # 䴟 0x4d20:yǎo # 䴠 0x4d21:lì # 䴡 0x4d22:mí # 䴢 0x4d26:rén,yín # 䴦 0x4d29:piáo # 䴩 0x4d2a:lù # 䴪 0x4d2b:líng # 䴫 0x4d2c:yì # 䴬 0x4d2d:cái # 䴭 0x4d2e:shàn # 䴮 0x4d30:shú # 䴰 0x4d31:tuō # 䴱 0x4d32:mò # 䴲 0x4d33:hè,huá # 䴳 0x4d34:tiè,nián # 䴴 0x4d35:bǐng,zhuó # 䴵 0x4d36:péng # 䴶 0x4d37:hún # 䴷 0x4d39:guǒ # 䴹 0x4d3a:bù,cǎi,chàn # 䴺 0x4d3b:lí # 䴻 0x4d3c:chǎn,chàn # 䴼 0x4d3d:bài,pí # 䴽 0x4d3e:cuó,cuò,yè,zhěn,zǐ # 䴾 0x4d3f:méng # 䴿 0x4d40:suǒ # 䵀 0x4d41:qiàng # 䵁 0x4d42:zhí # 䵂 0x4d43:kuàng # 䵃 0x4d44:bí,bó,fèng,pěng # 䵄 0x4d45:áo # 䵅 0x4d46:méng # 䵆 0x4d47:xiàn # 䵇 0x4d49:tóu # 䵉 0x4d4b:wěi # 䵋 0x4d4f:lǎo # 䵏 0x4d50:chǎn,chàn # 䵐 0x4d51:nì # 䵑 0x4d52:nì # 䵒 0x4d53:lí # 䵓 0x4d54:dǒng # 䵔 0x4d55:jù # 䵕 0x4d56:jiàn,qiàn,xiàn # 䵖 0x4d57:fú,bó # 䵗 0x4d58:shà,shài # 䵘 0x4d59:zhǎ # 䵙 0x4d5a:tǎo # 䵚 0x4d5b:jiàn,xiàn # 䵛 0x4d5c:nǒng # 䵜 0x4d5d:yà,yì # 䵝 0x4d5e:jìng,qíng # 䵞 0x4d5f:gǎn # 䵟 0x4d60:dí # 䵠 0x4d61:jiǎn # 䵡 0x4d62:mèi,wèi # 䵢 0x4d63:dá,zhǎn # 䵣 0x4d64:jiǎn # 䵤 0x4d65:shè,wán,yìng,yù # 䵥 0x4d66:xiè # 䵦 0x4d67:zài # 䵧 0x4d68:máng # 䵨 0x4d69:lí # 䵩 0x4d6a:gùn # 䵪 0x4d6b:yù # 䵫 0x4d6c:tà # 䵬 0x4d6d:zhè # 䵭 0x4d6e:yàng # 䵮 0x4d6f:tuǎn # 䵯 0x4d71:hè,xì # 䵱 0x4d72:diào # 䵲 0x4d73:wèi # 䵳 0x4d74:yùn,zèng # 䵴 0x4d75:zhá,zhuó,chuā # 䵵 0x4d76:qú # 䵶 0x4d7a:tǐng # 䵺 0x4d7b:gǔ,hú,huì # 䵻 0x4d7d:cà # 䵽 0x4d7e:fú # 䵾 0x4d7f:tiè # 䵿 0x4d80:tà # 䶀 0x4d81:tà # 䶁 0x4d82:zhuó # 䶂 0x4d83:hán # 䶃 0x4d84:píng # 䶄 0x4d85:hé # 䶅 0x4d87:zhòu # 䶇 0x4d88:bó # 䶈 0x4d89:liú # 䶉 0x4d8a:nǜ # 䶊 0x4d8c:pào # 䶌 0x4d8d:dì,tì # 䶍 0x4d8e:shà # 䶎 0x4d8f:tǐ,tì # 䶏 0x4d90:wài,huì # 䶐 0x4d91:tì # 䶑 0x4d92:qí # 䶒 0x4d93:jì,qì # 䶓 0x4d94:chí,mín # 䶔 0x4d95:pá # 䶕 0x4d96:jìn,qín # 䶖 0x4d97:qiā,qiǎ,kè # 䶗 0x4d98:lì # 䶘 0x4d99:jù # 䶙 0x4d9a:qǔ # 䶚 0x4d9b:là,liè # 䶛 0x4d9c:gù # 䶜 0x4d9d:qià,xiá # 䶝 0x4d9e:qí # 䶞 0x4d9f:xiàn # 䶟 0x4da0:jiǎn,xián # 䶠 0x4da1:shí,zé,zhì # 䶡 0x4da2:xián,jiān # 䶢 0x4da3:ái # 䶣 0x4da4:huá # 䶤 0x4da5:jǔ,zhā # 䶥 0x4da6:zé # 䶦 0x4da7:yǎo # 䶧 0x4da9:jì # 䶩 0x4daa:chá # 䶪 0x4dab:kǎn,yán,yàn # 䶫 0x4dae:yǎn # 䶮 0x4db1:tóng # 䶱 0x4db2:nán,nàn,rán # 䶲 0x4db3:yuè # 䶳 0x4db5:chí,shǐ # 䶵 0x4e00:yī # 一 0x4e01:dīng,zhēng # 丁 0x4e02:kǎo,qiǎo,yú # 丂 0x4e03:qī # 七 0x4e04:shàng # 丄 0x4e05:xià # 丅 0x4e07:wàn,mò # 万 0x4e08:zhàng # 丈 0x4e09:sān # 三 0x4e0a:shàng,shǎng # 上 0x4e0b:xià # 下 0x4e0c:qí,jī # 丌 0x4e0d:bù,fǒu # 不 0x4e0e:yǔ,yù,yú # 与 0x4e0f:miǎn # 丏 0x4e10:gài # 丐 0x4e11:chǒu # 丑 0x4e12:chǒu # 丒 0x4e13:zhuān # 专 0x4e14:qiě,jū # 且 0x4e15:pī # 丕 0x4e16:shì # 世 0x4e17:shì # 丗 0x4e18:qiū # 丘 0x4e19:bǐng # 丙 0x4e1a:yè # 业 0x4e1b:cóng # 丛 0x4e1c:dōng # 东 0x4e1d:sī # 丝 0x4e1e:chéng # 丞 0x4e1f:diū # 丟 0x4e20:qiū # 丠 0x4e21:liǎng # 両 0x4e22:diū # 丢 0x4e23:yǒu # 丣 0x4e24:liǎng # 两 0x4e25:yán # 严 0x4e26:bìng # 並 0x4e27:sāng,sàng # 丧 0x4e28:gǔn # 丨 0x4e29:jiū # 丩 0x4e2a:gè,gě # 个 0x4e2b:yā # 丫 0x4e2c:pán # 丬 0x4e2d:zhōng,zhòng # 中 0x4e2e:jǐ # 丮 0x4e2f:jiè # 丯 0x4e30:fēng # 丰 0x4e31:guàn,kuàng # 丱 0x4e32:chuàn # 串 0x4e33:chǎn # 丳 0x4e34:lín # 临 0x4e35:zhuó # 丵 0x4e36:zhǔ # 丶 0x4e38:wán # 丸 0x4e39:dān # 丹 0x4e3a:wéi,wèi # 为 0x4e3b:zhǔ # 主 0x4e3c:jǐng # 丼 0x4e3d:lì,lí # 丽 0x4e3e:jǔ # 举 0x4e3f:piě # 丿 0x4e40:fú # 乀 0x4e41:yí,jí # 乁 0x4e42:yì # 乂 0x4e43:nǎi # 乃 0x4e45:jiǔ # 久 0x4e46:jiǔ # 乆 0x4e47:tuō,zhé # 乇 0x4e48:me,mó,ma,yāo # 么 0x4e49:yì # 义 0x4e4b:zhī # 之 0x4e4c:wū # 乌 0x4e4d:zhà # 乍 0x4e4e:hū # 乎 0x4e4f:fá # 乏 0x4e50:lè,yuè,yào,lào # 乐 0x4e51:yín # 乑 0x4e52:pīng # 乒 0x4e53:pāng # 乓 0x4e54:qiáo # 乔 0x4e55:hǔ # 乕 0x4e56:guāi # 乖 0x4e57:chéng,shèng # 乗 0x4e58:chéng,shèng # 乘 0x4e59:yǐ # 乙 0x4e5a:háo,yǐ # 乚 0x4e5c:miē,niè # 乜 0x4e5d:jiǔ # 九 0x4e5e:qǐ # 乞 0x4e5f:yě # 也 0x4e60:xí # 习 0x4e61:xiāng # 乡 0x4e62:gài # 乢 0x4e63:jiǔ # 乣 0x4e66:shū # 书 0x4e68:shǐ # 乨 0x4e69:jī # 乩 0x4e6a:náng # 乪 0x4e6b:jiā # 乫 0x4e6d:shí # 乭 0x4e70:mǎi # 买 0x4e71:luàn # 乱 0x4e73:rǔ # 乳 0x4e74:xué # 乴 0x4e75:yǎn # 乵 0x4e76:fǔ # 乶 0x4e77:shā # 乷 0x4e78:nǎ # 乸 0x4e79:qián # 乹 0x4e7e:qián,gān # 乾 0x4e7f:zhì,luàn # 乿 0x4e80:guī # 亀 0x4e81:qián,gān # 亁 0x4e82:luàn # 亂 0x4e83:lǐn,lìn # 亃 0x4e84:yì # 亄 0x4e85:jué # 亅 0x4e86:le,liǎo # 了 0x4e88:yú,yǔ # 予 0x4e89:zhēng # 争 0x4e8a:shì # 亊 0x4e8b:shì # 事 0x4e8c:èr # 二 0x4e8d:chù # 亍 0x4e8e:yú # 于 0x4e8f:kuī # 亏 0x4e90:yú # 亐 0x4e91:yún # 云 0x4e92:hù # 互 0x4e93:qí # 亓 0x4e94:wǔ # 五 0x4e95:jǐng # 井 0x4e96:sì # 亖 0x4e97:suì # 亗 0x4e98:gèn # 亘 0x4e99:gèn # 亙 0x4e9a:yà # 亚 0x4e9b:xiē,suò # 些 0x4e9c:yà # 亜 0x4e9d:qí,zhāi # 亝 0x4e9e:yā,yà # 亞 0x4e9f:jí,qì # 亟 0x4ea0:tóu # 亠 0x4ea1:wáng,wú # 亡 0x4ea2:kàng # 亢 0x4ea3:dà # 亣 0x4ea4:jiāo # 交 0x4ea5:hài # 亥 0x4ea6:yì # 亦 0x4ea7:chǎn # 产 0x4ea8:hēng,pēng # 亨 0x4ea9:mǔ # 亩 0x4eab:xiǎng # 享 0x4eac:jīng # 京 0x4ead:tíng # 亭 0x4eae:liàng # 亮 0x4eaf:xiǎng # 亯 0x4eb0:jīng # 亰 0x4eb1:yè # 亱 0x4eb2:qīn,qìng # 亲 0x4eb3:bó # 亳 0x4eb4:yòu # 亴 0x4eb5:xiè # 亵 0x4eb6:dǎn,dàn # 亶 0x4eb7:lián # 亷 0x4eb8:duǒ # 亸 0x4eb9:wěi,mén # 亹 0x4eba:rén # 人 0x4ebb:rén # 亻 0x4ebc:jí # 亼 0x4ebe:wáng # 亾 0x4ebf:yì # 亿 0x4ec0:shí,shén # 什 0x4ec1:rén # 仁 0x4ec2:lè # 仂 0x4ec3:dīng # 仃 0x4ec4:zè # 仄 0x4ec5:jǐn,jìn # 仅 0x4ec6:pū,pú # 仆 0x4ec7:chóu,qiú # 仇 0x4ec8:bā # 仈 0x4ec9:zhǎng # 仉 0x4eca:jīn # 今 0x4ecb:jiè # 介 0x4ecc:bīng # 仌 0x4ecd:réng # 仍 0x4ece:cóng,zòng # 从 0x4ecf:fó # 仏 0x4ed0:jīn,sǎn # 仐 0x4ed1:lún # 仑 0x4ed3:cāng # 仓 0x4ed4:zī,zǐ,zǎi # 仔 0x4ed5:shì # 仕 0x4ed6:tā # 他 0x4ed7:zhàng # 仗 0x4ed8:fù # 付 0x4ed9:xiān # 仙 0x4eda:xiān # 仚 0x4edb:tuō,chà,duó # 仛 0x4edc:hóng # 仜 0x4edd:tóng # 仝 0x4ede:rèn # 仞 0x4edf:qiān # 仟 0x4ee0:gǎn,hàn # 仠 0x4ee1:yì,gē # 仡 0x4ee2:bó # 仢 0x4ee3:dài # 代 0x4ee4:líng,lǐng,lìng # 令 0x4ee5:yǐ # 以 0x4ee6:chào # 仦 0x4ee7:cháng,zhǎng # 仧 0x4ee8:sā # 仨 0x4eea:yí # 仪 0x4eeb:mù # 仫 0x4eec:mén # 们 0x4eed:rèn # 仭 0x4eee:fǎn # 仮 0x4eef:chào,miǎo # 仯 0x4ef0:yǎng,áng # 仰 0x4ef1:qián # 仱 0x4ef2:zhòng # 仲 0x4ef3:pǐ,pí # 仳 0x4ef4:wò # 仴 0x4ef5:wǔ # 仵 0x4ef6:jiàn # 件 0x4ef7:jià,jiè,jie # 价 0x4ef8:yǎo,fó # 仸 0x4ef9:fēng # 仹 0x4efa:cāng # 仺 0x4efb:rèn,rén # 任 0x4efc:wáng # 仼 0x4efd:fèn,bīn # 份 0x4efe:dī # 仾 0x4eff:fǎng # 仿 0x4f00:zhōng # 伀 0x4f01:qǐ # 企 0x4f02:pèi # 伂 0x4f03:yú # 伃 0x4f04:diào # 伄 0x4f05:dùn # 伅 0x4f06:wěn # 伆 0x4f07:yì # 伇 0x4f08:xǐn # 伈 0x4f09:kàng # 伉 0x4f0a:yī # 伊 0x4f0b:jí # 伋 0x4f0c:ài # 伌 0x4f0d:wǔ # 伍 0x4f0e:jì,qí # 伎 0x4f0f:fú # 伏 0x4f10:fá # 伐 0x4f11:xiū,xǔ # 休 0x4f12:jìn,yín # 伒 0x4f13:pī # 伓 0x4f14:dǎn # 伔 0x4f15:fū # 伕 0x4f16:tǎng # 伖 0x4f17:zhòng # 众 0x4f18:yōu # 优 0x4f19:huǒ # 伙 0x4f1a:huì,kuài # 会 0x4f1b:yǔ # 伛 0x4f1c:cuì # 伜 0x4f1d:yún # 伝 0x4f1e:sǎn # 伞 0x4f1f:wěi # 伟 0x4f20:chuán,zhuàn # 传 0x4f21:chē,jū # 伡 0x4f22:yá # 伢 0x4f23:qiàn # 伣 0x4f24:shāng # 伤 0x4f25:chāng # 伥 0x4f26:lún # 伦 0x4f27:cāng,chen # 伧 0x4f28:xùn # 伨 0x4f29:xìn # 伩 0x4f2a:wěi # 伪 0x4f2b:zhù # 伫 0x4f2d:xián,xuán # 伭 0x4f2e:nú,nǔ # 伮 0x4f2f:bó,bǎi,bà # 伯 0x4f30:gū,gù # 估 0x4f31:nǐ # 伱 0x4f32:nǐ,nì # 伲 0x4f33:xiè # 伳 0x4f34:bàn # 伴 0x4f35:xù # 伵 0x4f36:líng # 伶 0x4f37:zhòu # 伷 0x4f38:shēn # 伸 0x4f39:qū # 伹 0x4f3a:sì,cì # 伺 0x4f3b:bēng # 伻 0x4f3c:sì,shì # 似 0x4f3d:qié,jiā,gā # 伽 0x4f3e:pī # 伾 0x4f3f:yì # 伿 0x4f40:sì # 佀 0x4f41:yǐ,chì # 佁 0x4f42:zhēng # 佂 0x4f43:diàn,tián # 佃 0x4f44:hān,gàn # 佄 0x4f45:mài # 佅 0x4f46:dàn # 但 0x4f47:zhù # 佇 0x4f48:bù # 佈 0x4f49:qū # 佉 0x4f4a:bǐ # 佊 0x4f4b:zhāo,shào # 佋 0x4f4c:cǐ # 佌 0x4f4d:wèi # 位 0x4f4e:dī # 低 0x4f4f:zhù # 住 0x4f50:zuǒ # 佐 0x4f51:yòu # 佑 0x4f52:yǎng # 佒 0x4f53:tǐ,tī # 体 0x4f54:zhàn,diān # 佔 0x4f55:hé,hē,hè # 何 0x4f56:bì # 佖 0x4f57:tuó # 佗 0x4f58:shé # 佘 0x4f59:yú # 余 0x4f5a:yì,dié # 佚 0x4f5b:fó,fú,bì,bó # 佛 0x4f5c:zuò # 作 0x4f5d:gōu,kòu # 佝 0x4f5e:nìng # 佞 0x4f5f:tóng # 佟 0x4f60:nǐ # 你 0x4f61:xiān # 佡 0x4f62:qú # 佢 0x4f63:yōng,yòng # 佣 0x4f64:wǎ # 佤 0x4f65:qiān # 佥 0x4f67:kǎ # 佧 0x4f69:pèi # 佩 0x4f6a:huí,huái # 佪 0x4f6b:gé,hè # 佫 0x4f6c:lǎo # 佬 0x4f6d:xiáng # 佭 0x4f6e:gé # 佮 0x4f6f:yáng # 佯 0x4f70:bǎi # 佰 0x4f71:fǎ # 佱 0x4f72:mǐng # 佲 0x4f73:jiā # 佳 0x4f74:èr,nài # 佴 0x4f75:bìng # 併 0x4f76:jí # 佶 0x4f77:hěn # 佷 0x4f78:huó # 佸 0x4f79:guǐ # 佹 0x4f7a:quán # 佺 0x4f7b:tiāo # 佻 0x4f7c:jiǎo # 佼 0x4f7d:cì # 佽 0x4f7e:yì # 佾 0x4f7f:shǐ # 使 0x4f80:xíng # 侀 0x4f81:shēn # 侁 0x4f82:tuō # 侂 0x4f83:kǎn # 侃 0x4f84:zhí # 侄 0x4f85:gāi # 侅 0x4f86:lái # 來 0x4f87:yí # 侇 0x4f88:chǐ # 侈 0x4f89:kuǎ # 侉 0x4f8a:gōng # 侊 0x4f8b:lì # 例 0x4f8c:yīn # 侌 0x4f8d:shì # 侍 0x4f8e:mǐ # 侎 0x4f8f:zhū # 侏 0x4f90:xù # 侐 0x4f91:yòu # 侑 0x4f92:ān # 侒 0x4f93:lù # 侓 0x4f94:móu # 侔 0x4f95:ér # 侕 0x4f96:lún # 侖 0x4f97:dòng,tóng,tǒng # 侗 0x4f98:chà # 侘 0x4f99:chì # 侙 0x4f9a:xùn # 侚 0x4f9b:gōng,gòng # 供 0x4f9c:zhōu # 侜 0x4f9d:yī # 依 0x4f9e:rú # 侞 0x4f9f:cún,jiàn # 侟 0x4fa0:xiá # 侠 0x4fa1:sì # 価 0x4fa2:dài # 侢 0x4fa3:lǚ # 侣 0x4fa5:jiǎo,yáo # 侥 0x4fa6:zhēn # 侦 0x4fa7:cè,zè,zhāi # 侧 0x4fa8:qiáo # 侨 0x4fa9:kuài # 侩 0x4faa:chái # 侪 0x4fab:nìng # 侫 0x4fac:nóng # 侬 0x4fad:jǐn # 侭 0x4fae:wǔ # 侮 0x4faf:hóu,hòu # 侯 0x4fb0:jiǒng # 侰 0x4fb1:chěng,tǐng # 侱 0x4fb2:zhèn,zhēn # 侲 0x4fb3:zuò # 侳 0x4fb4:hào # 侴 0x4fb5:qīn # 侵 0x4fb6:lǚ # 侶 0x4fb7:jú # 侷 0x4fb8:shù,dōu # 侸 0x4fb9:tǐng # 侹 0x4fba:shèn # 侺 0x4fbb:tuó,tuì # 侻 0x4fbc:bó # 侼 0x4fbd:nán # 侽 0x4fbe:xiāo # 侾 0x4fbf:biàn,pián # 便 0x4fc0:tuǐ # 俀 0x4fc1:yǔ # 俁 0x4fc2:xì # 係 0x4fc3:cù # 促 0x4fc4:é # 俄 0x4fc5:qiú # 俅 0x4fc6:xú # 俆 0x4fc7:guàng # 俇 0x4fc8:kù # 俈 0x4fc9:wù # 俉 0x4fca:jùn # 俊 0x4fcb:yì # 俋 0x4fcc:fǔ # 俌 0x4fcd:liáng # 俍 0x4fce:zǔ # 俎 0x4fcf:qiào,xiào # 俏 0x4fd0:lì # 俐 0x4fd1:yǒng # 俑 0x4fd2:hùn # 俒 0x4fd3:jìng # 俓 0x4fd4:qiàn # 俔 0x4fd5:sàn # 俕 0x4fd6:pěi # 俖 0x4fd7:sú # 俗 0x4fd8:fú # 俘 0x4fd9:xī # 俙 0x4fda:lǐ # 俚 0x4fdb:fǔ,miǎn # 俛 0x4fdc:pīng # 俜 0x4fdd:bǎo # 保 0x4fde:yú,yù,shù # 俞 0x4fdf:sì,qí # 俟 0x4fe0:xiá # 俠 0x4fe1:xìn,shēn # 信 0x4fe2:xiū # 俢 0x4fe3:yǔ # 俣 0x4fe4:dì # 俤 0x4fe5:chē,jū # 俥 0x4fe6:chóu # 俦 0x4fe8:yǎn # 俨 0x4fe9:liǎng,liǎ # 俩 0x4fea:lì # 俪 0x4feb:lái # 俫 0x4fed:jiǎn # 俭 0x4fee:xiū # 修 0x4fef:fǔ # 俯 0x4ff0:huò # 俰 0x4ff1:jù # 俱 0x4ff2:xiào # 俲 0x4ff3:pái # 俳 0x4ff4:jiàn # 俴 0x4ff5:biào # 俵 0x4ff6:chù,tì # 俶 0x4ff7:fèi # 俷 0x4ff8:fèng # 俸 0x4ff9:yà # 俹 0x4ffa:ǎn # 俺 0x4ffb:bèi # 俻 0x4ffc:yù # 俼 0x4ffd:xīn # 俽 0x4ffe:bǐ # 俾 0x4fff:hǔ,chí # 俿 0x5000:chāng # 倀 0x5001:zhī # 倁 0x5002:bìng # 倂 0x5003:jiù # 倃 0x5004:yáo # 倄 0x5005:cuì,zú # 倅 0x5006:liǎng,liǎ # 倆 0x5007:wǎn # 倇 0x5008:lái # 倈 0x5009:cāng # 倉 0x500a:zǒng # 倊 0x500b:gè,gě # 個 0x500c:guān # 倌 0x500d:bèi # 倍 0x500e:tiǎn # 倎 0x500f:shū # 倏 0x5010:shū # 倐 0x5011:mén # 們 0x5012:dǎo,dào # 倒 0x5013:tán,tàn # 倓 0x5014:jué,juè # 倔 0x5015:chuí # 倕 0x5016:xìng # 倖 0x5017:péng # 倗 0x5018:tǎng,cháng # 倘 0x5019:hòu # 候 0x501a:yǐ # 倚 0x501b:qī # 倛 0x501c:tì # 倜 0x501d:gàn # 倝 0x501e:liàng,jìng # 倞 0x501f:jiè # 借 0x5020:suī # 倠 0x5021:chàng,chāng # 倡 0x5022:jié # 倢 0x5023:fǎng # 倣 0x5024:zhí # 値 0x5025:kōng,kǒng # 倥 0x5026:juàn # 倦 0x5027:zōng # 倧 0x5028:jù # 倨 0x5029:qiàn # 倩 0x502a:ní # 倪 0x502b:lún # 倫 0x502c:zhuō # 倬 0x502d:wō,wēi # 倭 0x502e:luǒ # 倮 0x502f:sōng # 倯 0x5030:lèng # 倰 0x5031:hùn # 倱 0x5032:dōng # 倲 0x5033:zì # 倳 0x5034:bèn # 倴 0x5035:wǔ # 倵 0x5036:jù # 倶 0x5037:nǎi # 倷 0x5038:cǎi # 倸 0x5039:jiǎn # 倹 0x503a:zhài # 债 0x503b:yē # 倻 0x503c:zhí # 值 0x503d:shà # 倽 0x503e:qīng # 倾 0x5040:yīng # 偀 0x5041:chēng,chèn # 偁 0x5042:qián # 偂 0x5043:yǎn # 偃 0x5044:ruǎn # 偄 0x5045:zhòng,tóng # 偅 0x5046:chǔn # 偆 0x5047:jiǎ,jià # 假 0x5048:jì,jié # 偈 0x5049:wěi # 偉 0x504a:yǔ # 偊 0x504b:bǐng,bìng # 偋 0x504c:ruò # 偌 0x504d:tí # 偍 0x504e:wēi # 偎 0x504f:piān # 偏 0x5050:yàn # 偐 0x5051:fēng # 偑 0x5052:tǎng,dàng # 偒 0x5053:wò # 偓 0x5054:è # 偔 0x5055:xié # 偕 0x5056:chě # 偖 0x5057:shěng # 偗 0x5058:kǎn # 偘 0x5059:dì # 偙 0x505a:zuò # 做 0x505b:chā # 偛 0x505c:tíng # 停 0x505d:bèi # 偝 0x505e:xiè # 偞 0x505f:huáng # 偟 0x5060:yǎo # 偠 0x5061:zhàn # 偡 0x5062:chǒu,qiào # 偢 0x5063:ān # 偣 0x5064:yóu # 偤 0x5065:jiàn # 健 0x5066:xū # 偦 0x5067:zhā # 偧 0x5068:cī # 偨 0x5069:fù # 偩 0x506a:bī # 偪 0x506b:zhì # 偫 0x506c:zǒng # 偬 0x506d:miǎn # 偭 0x506e:jí # 偮 0x506f:yǐ # 偯 0x5070:xiè # 偰 0x5071:xún # 偱 0x5072:cāi,sī # 偲 0x5073:duān # 偳 0x5074:cè,zè,zhāi # 側 0x5075:zhēn # 偵 0x5076:ǒu # 偶 0x5077:tōu # 偷 0x5078:tōu # 偸 0x5079:bèi # 偹 0x507a:zán,zá,zǎ # 偺 0x507b:lǚ,lóu # 偻 0x507c:jié # 偼 0x507d:wěi # 偽 0x507e:fèn # 偾 0x507f:cháng # 偿 0x5080:kuǐ,guī # 傀 0x5081:sǒu # 傁 0x5082:zhì,sī # 傂 0x5083:sù # 傃 0x5084:xiā # 傄 0x5085:fù # 傅 0x5086:yuàn,yuán # 傆 0x5087:rǒng # 傇 0x5088:lì # 傈 0x5089:nù # 傉 0x508a:yùn # 傊 0x508b:jiǎng,gòu # 傋 0x508c:mà # 傌 0x508d:bàng # 傍 0x508e:diān # 傎 0x508f:táng # 傏 0x5090:hào # 傐 0x5091:jié # 傑 0x5092:xī,xì # 傒 0x5093:shān # 傓 0x5094:qiàn,jiān # 傔 0x5095:què,jué # 傕 0x5096:cāng,chen # 傖 0x5097:chù # 傗 0x5098:sǎn # 傘 0x5099:bèi # 備 0x509a:xiào # 傚 0x509b:róng # 傛 0x509c:yáo # 傜 0x509d:tà,tàn # 傝 0x509e:suō # 傞 0x509f:yǎng # 傟 0x50a0:fá # 傠 0x50a1:bìng # 傡 0x50a2:jiā # 傢 0x50a3:dǎi # 傣 0x50a4:zài # 傤 0x50a5:tǎng # 傥 0x50a7:bīn # 傧 0x50a8:chǔ # 储 0x50a9:nuó # 傩 0x50aa:cān,càn # 傪 0x50ab:lěi # 傫 0x50ac:cuī # 催 0x50ad:yōng # 傭 0x50ae:zāo,cáo # 傮 0x50af:zǒng # 傯 0x50b0:péng # 傰 0x50b1:sǒng # 傱 0x50b2:ào # 傲 0x50b3:chuán,zhuàn # 傳 0x50b4:yǔ # 傴 0x50b5:zhài # 債 0x50b6:qī,còu # 傶 0x50b7:shāng # 傷 0x50b8:chuǎng # 傸 0x50b9:jìng # 傹 0x50ba:chì # 傺 0x50bb:shǎ # 傻 0x50bc:hàn # 傼 0x50bd:zhāng # 傽 0x50be:qīng # 傾 0x50bf:yān,yàn # 傿 0x50c0:dì # 僀 0x50c1:xiè # 僁 0x50c2:lǚ,lóu # 僂 0x50c3:bèi # 僃 0x50c4:piào,biāo # 僄 0x50c5:jǐn,jìn # 僅 0x50c6:liàn # 僆 0x50c7:lù # 僇 0x50c8:màn # 僈 0x50c9:qiān # 僉 0x50ca:xiān # 僊 0x50cb:tǎn,tàn # 僋 0x50cc:yíng # 僌 0x50cd:dòng # 働 0x50ce:zhuàn # 僎 0x50cf:xiàng # 像 0x50d0:shàn # 僐 0x50d1:qiáo # 僑 0x50d2:jiǒng # 僒 0x50d3:tuǐ,tuí # 僓 0x50d4:zǔn # 僔 0x50d5:pú # 僕 0x50d6:xī # 僖 0x50d7:láo # 僗 0x50d8:chǎng # 僘 0x50d9:guāng # 僙 0x50da:liáo # 僚 0x50db:qī # 僛 0x50dc:chēng,dēng # 僜 0x50dd:zhàn,zhuàn,chán # 僝 0x50de:wěi # 僞 0x50df:jī # 僟 0x50e0:bō # 僠 0x50e1:huì # 僡 0x50e2:chuǎn # 僢 0x50e3:tiě,jiàn # 僣 0x50e4:dàn # 僤 0x50e5:jiǎo,yáo # 僥 0x50e6:jiù # 僦 0x50e7:sēng # 僧 0x50e8:fèn # 僨 0x50e9:xiàn # 僩 0x50ea:yù,jú # 僪 0x50eb:è,wù,wū # 僫 0x50ec:jiāo # 僬 0x50ed:jiàn # 僭 0x50ee:tóng,zhuàng # 僮 0x50ef:lǐn # 僯 0x50f0:bó # 僰 0x50f1:gù # 僱 0x50f3:sù # 僳 0x50f4:xiàn # 僴 0x50f5:jiāng # 僵 0x50f6:mǐn # 僶 0x50f7:yè # 僷 0x50f8:jìn # 僸 0x50f9:jià,jie # 價 0x50fa:qiào # 僺 0x50fb:pì # 僻 0x50fc:fēng # 僼 0x50fd:zhòu # 僽 0x50fe:ài # 僾 0x50ff:sài # 僿 0x5100:yí # 儀 0x5101:jùn # 儁 0x5102:nóng # 儂 0x5103:chán,tǎn,shàn # 儃 0x5104:yì # 億 0x5105:dāng,dàng # 儅 0x5106:jǐng # 儆 0x5107:xuān # 儇 0x5108:kuài # 儈 0x5109:jiǎn # 儉 0x510a:chù # 儊 0x510b:dān,dàn # 儋 0x510c:jiǎo # 儌 0x510d:shǎ # 儍 0x510e:zài # 儎 0x5110:bīn,bìn # 儐 0x5111:án,àn # 儑 0x5112:rú # 儒 0x5113:tái # 儓 0x5114:chóu # 儔 0x5115:chái # 儕 0x5116:lán # 儖 0x5117:nǐ,yì # 儗 0x5118:jǐn # 儘 0x5119:qiàn # 儙 0x511a:méng # 儚 0x511b:wǔ # 儛 0x511c:níng # 儜 0x511d:qióng # 儝 0x511e:nǐ # 儞 0x511f:cháng # 償 0x5120:liè # 儠 0x5121:lěi # 儡 0x5122:lǚ # 儢 0x5123:kuǎng # 儣 0x5124:bào # 儤 0x5125:yù # 儥 0x5126:biāo # 儦 0x5127:zǎn # 儧 0x5128:zhì # 儨 0x5129:sì # 儩 0x512a:yōu # 優 0x512b:háo # 儫 0x512c:qìng # 儬 0x512d:chèn # 儭 0x512e:lì # 儮 0x512f:téng # 儯 0x5130:wěi # 儰 0x5131:lǒng,lóng,lòng # 儱 0x5132:chǔ # 儲 0x5133:chán,chàn # 儳 0x5134:ráng,xiāng # 儴 0x5135:shū # 儵 0x5136:huì,xié # 儶 0x5137:lì # 儷 0x5138:luó # 儸 0x5139:zǎn # 儹 0x513a:nuó # 儺 0x513b:tǎng # 儻 0x513c:yǎn # 儼 0x513d:léi # 儽 0x513e:nàng,nāng # 儾 0x513f:ér # 儿 0x5140:wù # 兀 0x5141:yǔn # 允 0x5142:zān # 兂 0x5143:yuán # 元 0x5144:xiōng # 兄 0x5145:chōng # 充 0x5146:zhào # 兆 0x5147:xiōng # 兇 0x5148:xiān # 先 0x5149:guāng # 光 0x514a:duì,ruì,yuè # 兊 0x514b:kè # 克 0x514c:duì,ruì,yuè # 兌 0x514d:miǎn # 免 0x514e:tù # 兎 0x514f:cháng,zhǎng # 兏 0x5150:ér # 児 0x5151:duì,ruì,yuè # 兑 0x5152:ér # 兒 0x5153:qīn,jīn,zàn # 兓 0x5154:tù # 兔 0x5155:sì # 兕 0x5156:yǎn # 兖 0x5157:yǎn # 兗 0x5158:shǐ # 兘 0x515a:dǎng # 党 0x515b:qiānkè # 兛 0x515c:dōu # 兜 0x515d:gōngfēn # 兝 0x515e:háokè # 兞 0x515f:shēn # 兟 0x5160:dōu # 兠 0x5162:jīng # 兢 0x5163:gōnglǐ # 兣 0x5164:huǎng # 兤 0x5165:rù # 入 0x5166:wáng # 兦 0x5167:nèi # 內 0x5168:quán # 全 0x5169:liǎng # 兩 0x516a:yú,shù # 兪 0x516b:bā # 八 0x516c:gōng # 公 0x516d:liù,lù # 六 0x516e:xī # 兮 0x5170:lán # 兰 0x5171:gòng,gōng # 共 0x5172:tiān # 兲 0x5173:guān # 关 0x5174:xīng,xìng # 兴 0x5175:bīng # 兵 0x5176:qí,jī # 其 0x5177:jù # 具 0x5178:diǎn # 典 0x5179:zī,cí # 兹 0x517b:yǎng # 养 0x517c:jiān # 兼 0x517d:shòu # 兽 0x517e:jì # 兾 0x517f:yì # 兿 0x5180:jì # 冀 0x5181:chǎn # 冁 0x5182:jiōng # 冂 0x5184:rǎn # 冄 0x5185:nèi,nà # 内 0x5187:mǎo # 冇 0x5188:gāng # 冈 0x5189:rǎn # 冉 0x518a:cè # 冊 0x518b:jiōng # 冋 0x518c:cè # 册 0x518d:zài # 再 0x518e:guǎ # 冎 0x518f:jiǒng # 冏 0x5190:mào # 冐 0x5191:zhòu # 冑 0x5192:mào,mò # 冒 0x5193:gòu # 冓 0x5194:xú # 冔 0x5195:miǎn # 冕 0x5196:mì # 冖 0x5197:rǒng # 冗 0x5198:yín,yóu # 冘 0x5199:xiě # 写 0x519a:kǎn # 冚 0x519b:jūn # 军 0x519c:nóng # 农 0x519d:yí # 冝 0x519e:mí # 冞 0x519f:shì # 冟 0x51a0:guān,guàn # 冠 0x51a1:měng # 冡 0x51a2:zhǒng # 冢 0x51a3:zuì # 冣 0x51a4:yuān # 冤 0x51a5:míng # 冥 0x51a6:kòu # 冦 0x51a8:fù # 冨 0x51a9:xiě # 冩 0x51aa:mì # 冪 0x51ab:bīng # 冫 0x51ac:dōng # 冬 0x51ad:tài # 冭 0x51ae:gāng # 冮 0x51af:féng,píng # 冯 0x51b0:bīng # 冰 0x51b1:hù # 冱 0x51b2:chōng,chòng # 冲 0x51b3:jué # 决 0x51b4:yà # 冴 0x51b5:kuàng # 况 0x51b6:yě # 冶 0x51b7:lěng # 冷 0x51b8:pàn # 冸 0x51b9:fā # 冹 0x51ba:mǐn # 冺 0x51bb:dòng # 冻 0x51bc:xiǎn # 冼 0x51bd:liè # 冽 0x51be:qià # 冾 0x51bf:jiān # 冿 0x51c0:jìng,chēng # 净 0x51c1:sōu # 凁 0x51c2:měi # 凂 0x51c3:tú # 凃 0x51c4:qī # 凄 0x51c5:gù # 凅 0x51c6:zhǔn # 准 0x51c7:sōng # 凇 0x51c8:jìng,chēng # 凈 0x51c9:liáng,liàng # 凉 0x51ca:qìng # 凊 0x51cb:diāo # 凋 0x51cc:líng # 凌 0x51cd:dòng # 凍 0x51ce:gàn # 凎 0x51cf:jiǎn # 减 0x51d0:yīn # 凐 0x51d1:còu # 凑 0x51d2:ái # 凒 0x51d3:lì # 凓 0x51d4:cāng # 凔 0x51d5:mǐng # 凕 0x51d7:cuī # 凗 0x51d8:sī # 凘 0x51d9:duó # 凙 0x51da:jìn # 凚 0x51db:lǐn # 凛 0x51dc:lǐn # 凜 0x51dd:níng # 凝 0x51de:xī # 凞 0x51df:dú # 凟 0x51e0:jī,jǐ # 几 0x51e1:fán # 凡 0x51e2:fán # 凢 0x51e3:fán # 凣 0x51e4:fèng # 凤 0x51e5:jū # 凥 0x51e6:chù,chǔ # 処 0x51e8:fēng # 凨 0x51eb:fú # 凫 0x51ec:fēng # 凬 0x51ed:píng # 凭 0x51ee:fēng # 凮 0x51ef:kǎi # 凯 0x51f0:huáng # 凰 0x51f1:kǎi # 凱 0x51f2:gān # 凲 0x51f3:dèng # 凳 0x51f4:píng # 凴 0x51f5:kǎn,qiǎn # 凵 0x51f6:xiōng # 凶 0x51f7:kuài # 凷 0x51f8:tū # 凸 0x51f9:āo,wā # 凹 0x51fa:chū # 出 0x51fb:jī # 击 0x51fc:dàng # 凼 0x51fd:hán # 函 0x51fe:hán # 凾 0x51ff:záo # 凿 0x5200:dāo # 刀 0x5201:diāo # 刁 0x5202:dāo # 刂 0x5203:rèn # 刃 0x5204:rèn # 刄 0x5205:chuāng # 刅 0x5206:fēn,fèn # 分 0x5207:qiē,qiè # 切 0x5208:yì # 刈 0x5209:jī # 刉 0x520a:kān # 刊 0x520b:qiàn # 刋 0x520c:cǔn # 刌 0x520d:chú # 刍 0x520e:wěn # 刎 0x520f:jī # 刏 0x5210:dǎn # 刐 0x5211:xíng # 刑 0x5212:huá,huà,huai,guò,guǒ # 划 0x5213:wán # 刓 0x5214:jué # 刔 0x5215:lí # 刕 0x5216:yuè # 刖 0x5217:liè # 列 0x5218:liú # 刘 0x5219:zé # 则 0x521a:gāng # 刚 0x521b:chuàng,chuāng # 创 0x521c:fú # 刜 0x521d:chū # 初 0x521e:qù # 刞 0x521f:diāo # 刟 0x5220:shān # 删 0x5221:mǐn # 刡 0x5222:líng # 刢 0x5223:zhōng # 刣 0x5224:pàn # 判 0x5225:bié,biè # 別 0x5226:jié # 刦 0x5227:jié # 刧 0x5228:páo,bào # 刨 0x5229:lì # 利 0x522a:shān # 刪 0x522b:bié,biè # 别 0x522c:chǎn,chàn # 刬 0x522d:jǐng # 刭 0x522e:guā # 刮 0x522f:gēng # 刯 0x5230:dào # 到 0x5231:chuàng # 刱 0x5232:kuī # 刲 0x5233:kū # 刳 0x5234:duò # 刴 0x5235:èr # 刵 0x5236:zhì # 制 0x5237:shuā,shuà # 刷 0x5238:quàn,xuàn # 券 0x5239:chà,shā # 刹 0x523a:cì,cī # 刺 0x523b:kè # 刻 0x523c:jié # 刼 0x523d:guì # 刽 0x523e:cì # 刾 0x523f:guì # 刿 0x5240:kǎi # 剀 0x5241:duò # 剁 0x5242:jì # 剂 0x5243:tì # 剃 0x5244:jǐng # 剄 0x5245:lóu # 剅 0x5246:luǒ # 剆 0x5247:zé # 則 0x5248:yuān # 剈 0x5249:cuò # 剉 0x524a:xiāo,xuē # 削 0x524b:kēi,kè # 剋 0x524c:là,lá # 剌 0x524d:qián # 前 0x524e:chà,shā # 剎 0x524f:chuàng # 剏 0x5250:guǎ # 剐 0x5251:jiàn # 剑 0x5252:cuò # 剒 0x5253:lí # 剓 0x5254:tī # 剔 0x5255:fèi # 剕 0x5256:pōu # 剖 0x5257:chǎn,chàn # 剗 0x5258:qí # 剘 0x5259:chuàng # 剙 0x525a:zì # 剚 0x525b:gāng # 剛 0x525c:wān # 剜 0x525d:bāo,bō # 剝 0x525e:jī # 剞 0x525f:duō # 剟 0x5260:qíng # 剠 0x5261:yǎn,shàn # 剡 0x5262:dū,zhuó # 剢 0x5263:jiàn # 剣 0x5264:jì # 剤 0x5265:bāo,bō # 剥 0x5266:yān # 剦 0x5267:jù # 剧 0x5268:huò # 剨 0x5269:shèng # 剩 0x526a:jiǎn # 剪 0x526b:duó # 剫 0x526c:zhì,duān # 剬 0x526d:wū # 剭 0x526e:guǎ # 剮 0x526f:fù,pì # 副 0x5270:shèng # 剰 0x5271:jiàn # 剱 0x5272:gē # 割 0x5273:dá,zhá # 剳 0x5274:kǎi # 剴 0x5275:chuàng,chuāng # 創 0x5276:chuán # 剶 0x5277:chǎn # 剷 0x5278:tuán,zhuān # 剸 0x5279:lù,jiū # 剹 0x527a:lí # 剺 0x527b:pēng # 剻 0x527c:shān # 剼 0x527d:piāo # 剽 0x527e:kōu # 剾 0x527f:jiǎo,chāo # 剿 0x5280:guā # 劀 0x5281:qiāo # 劁 0x5282:jué # 劂 0x5283:huá,huà # 劃 0x5284:zhā,zhá # 劄 0x5285:zhuó # 劅 0x5286:lián # 劆 0x5287:jù # 劇 0x5288:pī,pǐ # 劈 0x5289:liú # 劉 0x528a:guì # 劊 0x528b:jiǎo,chāo # 劋 0x528c:guì # 劌 0x528d:jiàn # 劍 0x528e:jiàn # 劎 0x528f:tāng # 劏 0x5290:huō # 劐 0x5291:jì # 劑 0x5292:jiàn # 劒 0x5293:yì # 劓 0x5294:jiàn # 劔 0x5295:zhì # 劕 0x5296:chán # 劖 0x5297:zuān # 劗 0x5298:mó # 劘 0x5299:lí # 劙 0x529a:zhú # 劚 0x529b:lì # 力 0x529c:yà # 劜 0x529d:quàn # 劝 0x529e:bàn # 办 0x529f:gōng # 功 0x52a0:jiā # 加 0x52a1:wù # 务 0x52a2:mài # 劢 0x52a3:liè # 劣 0x52a4:jìn,jìng # 劤 0x52a5:kēng # 劥 0x52a6:xié,liè # 劦 0x52a7:zhǐ # 劧 0x52a8:dòng # 动 0x52a9:zhù,chú # 助 0x52aa:nǔ # 努 0x52ab:jié # 劫 0x52ac:qú # 劬 0x52ad:shào # 劭 0x52ae:yì # 劮 0x52af:zhǔ # 劯 0x52b0:miǎo # 劰 0x52b1:lì # 励 0x52b2:jìn,jìng # 劲 0x52b3:láo # 劳 0x52b4:láo # 労 0x52b5:juàn # 劵 0x52b6:kǒu # 劶 0x52b7:yáng # 劷 0x52b8:wā # 劸 0x52b9:xiào # 効 0x52ba:móu # 劺 0x52bb:kuāng # 劻 0x52bc:jié # 劼 0x52bd:liè # 劽 0x52be:hé # 劾 0x52bf:shì # 势 0x52c0:kè # 勀 0x52c1:jìn,jìng # 勁 0x52c2:gào # 勂 0x52c3:bó,bèi # 勃 0x52c4:mǐn # 勄 0x52c5:chì # 勅 0x52c6:láng # 勆 0x52c7:yǒng # 勇 0x52c8:yǒng # 勈 0x52c9:miǎn # 勉 0x52ca:kè # 勊 0x52cb:xūn # 勋 0x52cc:juàn,juān # 勌 0x52cd:qíng # 勍 0x52ce:lù # 勎 0x52cf:bù # 勏 0x52d0:měng # 勐 0x52d1:chì # 勑 0x52d2:lè,lēi # 勒 0x52d3:kài # 勓 0x52d4:miǎn # 勔 0x52d5:dòng # 動 0x52d6:xù # 勖 0x52d7:xù # 勗 0x52d8:kān # 勘 0x52d9:wù # 務 0x52da:yì # 勚 0x52db:xūn # 勛 0x52dc:wěng,yǎng # 勜 0x52dd:shèng # 勝 0x52de:láo # 勞 0x52df:mù # 募 0x52e0:lù # 勠 0x52e1:piāo # 勡 0x52e2:shì # 勢 0x52e3:jì # 勣 0x52e4:qín # 勤 0x52e5:jiàng # 勥 0x52e6:jiǎo,chāo # 勦 0x52e7:quàn # 勧 0x52e8:xiàng # 勨 0x52e9:yì # 勩 0x52ea:qiāo # 勪 0x52eb:fān # 勫 0x52ec:juān # 勬 0x52ed:tóng,dòng # 勭 0x52ee:jù # 勮 0x52ef:dān # 勯 0x52f0:xié # 勰 0x52f1:mài # 勱 0x52f2:xūn # 勲 0x52f3:xūn # 勳 0x52f4:lǜ # 勴 0x52f5:lì # 勵 0x52f6:chè # 勶 0x52f7:ráng,xiāng # 勷 0x52f8:quàn # 勸 0x52f9:bāo # 勹 0x52fa:sháo # 勺 0x52fb:yún # 勻 0x52fc:jiū # 勼 0x52fd:bào # 勽 0x52fe:gōu,gòu # 勾 0x52ff:wù # 勿 0x5300:yún # 匀 0x5303:gài # 匃 0x5304:gài # 匄 0x5305:bāo # 包 0x5306:cōng # 匆 0x5308:xiōng # 匈 0x5309:pēng # 匉 0x530a:jū # 匊 0x530b:táo,yáo # 匋 0x530c:gé # 匌 0x530d:pú # 匍 0x530e:è # 匎 0x530f:páo # 匏 0x5310:fú # 匐 0x5311:gōng # 匑 0x5312:dá # 匒 0x5313:jiù # 匓 0x5314:gōng # 匔 0x5315:bǐ # 匕 0x5316:huà,huā # 化 0x5317:běi,bèi # 北 0x5318:nǎo # 匘 0x5319:chí,shi # 匙 0x531a:fāng # 匚 0x531b:jiù # 匛 0x531c:yí # 匜 0x531d:zā # 匝 0x531e:jiàng # 匞 0x531f:kàng # 匟 0x5320:jiàng # 匠 0x5321:kuāng # 匡 0x5322:hū # 匢 0x5323:xiá # 匣 0x5324:qū # 匤 0x5325:fán # 匥 0x5326:guǐ # 匦 0x5327:qiè # 匧 0x5328:zāng,cáng # 匨 0x5329:kuāng # 匩 0x532a:fěi # 匪 0x532b:hū # 匫 0x532c:yǔ # 匬 0x532d:guǐ # 匭 0x532e:kuì,guì # 匮 0x532f:huì # 匯 0x5330:dān # 匰 0x5331:kuì,guì # 匱 0x5332:lián # 匲 0x5333:lián # 匳 0x5334:suǎn # 匴 0x5335:dú # 匵 0x5336:jiù # 匶 0x5337:jué # 匷 0x5338:xì # 匸 0x5339:pǐ # 匹 0x533a:qū,ōu # 区 0x533b:yī # 医 0x533c:kē,qià # 匼 0x533d:yǎn,yàn # 匽 0x533e:biǎn # 匾 0x533f:nì # 匿 0x5340:qū,ōu # 區 0x5341:shí # 十 0x5342:xùn # 卂 0x5343:qiān # 千 0x5344:niàn # 卄 0x5345:sà # 卅 0x5346:zú # 卆 0x5347:shēng # 升 0x5348:wǔ # 午 0x5349:huì # 卉 0x534a:bàn # 半 0x534b:shì # 卋 0x534c:xì # 卌 0x534d:wàn # 卍 0x534e:huá,huà,huā # 华 0x534f:xié # 协 0x5350:wàn # 卐 0x5351:bēi # 卑 0x5352:zú,cù # 卒 0x5353:zhuó # 卓 0x5354:xié # 協 0x5355:dān,shàn,chán # 单 0x5356:mài # 卖 0x5357:nán,nā # 南 0x5358:dān # 単 0x5359:jí # 卙 0x535a:bó # 博 0x535b:shuài,lǜ # 卛 0x535c:bǔ,bo # 卜 0x535d:guàn,kuàng # 卝 0x535e:biàn # 卞 0x535f:bǔ # 卟 0x5360:zhān,zhàn # 占 0x5361:kǎ,qiǎ # 卡 0x5362:lú # 卢 0x5363:yǒu # 卣 0x5364:lǔ # 卤 0x5365:xī # 卥 0x5366:guà # 卦 0x5367:wò # 卧 0x5368:xiè # 卨 0x5369:jié # 卩 0x536a:jié # 卪 0x536b:wèi # 卫 0x536c:yǎng,áng # 卬 0x536d:qióng # 卭 0x536e:zhī # 卮 0x536f:mǎo # 卯 0x5370:yìn # 印 0x5371:wēi # 危 0x5372:shào # 卲 0x5373:jí # 即 0x5374:què # 却 0x5375:luǎn # 卵 0x5376:chǐ # 卶 0x5377:juàn,juǎn # 卷 0x5378:xiè # 卸 0x5379:xù # 卹 0x537a:jǐn # 卺 0x537b:què # 卻 0x537c:wù # 卼 0x537d:jí # 卽 0x537e:è # 卾 0x537f:qīng # 卿 0x5380:xī # 厀 0x5382:chǎng,ān,hàn # 厂 0x5383:wēi,yán # 厃 0x5384:è # 厄 0x5385:tīng # 厅 0x5386:lì # 历 0x5387:zhé,zhái # 厇 0x5388:hàn,àn # 厈 0x5389:lì # 厉 0x538a:yǎ # 厊 0x538b:yā,yà # 压 0x538c:yàn # 厌 0x538d:shè # 厍 0x538e:dǐ # 厎 0x538f:zhǎ,zhǎi # 厏 0x5390:páng # 厐 0x5392:qiè # 厒 0x5393:yá # 厓 0x5394:zhì,shī # 厔 0x5395:cè # 厕 0x5396:máng # 厖 0x5397:tí # 厗 0x5398:lí # 厘 0x5399:shè # 厙 0x539a:hòu # 厚 0x539b:tīng # 厛 0x539c:zuī # 厜 0x539d:cuò # 厝 0x539e:fèi # 厞 0x539f:yuán # 原 0x53a0:cè # 厠 0x53a1:yuán # 厡 0x53a2:xiāng # 厢 0x53a3:yǎn # 厣 0x53a4:lì # 厤 0x53a5:jué # 厥 0x53a6:shà,xià # 厦 0x53a7:diān # 厧 0x53a8:chú # 厨 0x53a9:jiù # 厩 0x53aa:jǐn # 厪 0x53ab:áo # 厫 0x53ac:guǐ # 厬 0x53ad:yàn # 厭 0x53ae:sī # 厮 0x53af:lì # 厯 0x53b0:chǎng # 厰 0x53b1:qiān,lán # 厱 0x53b2:lì # 厲 0x53b3:yán # 厳 0x53b4:yǎn # 厴 0x53b5:yuán # 厵 0x53b6:sī,mǒu # 厶 0x53b7:gōng,hóng # 厷 0x53b8:lín,miǎo # 厸 0x53b9:róu,qiú # 厹 0x53ba:qù # 厺 0x53bb:qù # 去 0x53bd:lěi # 厽 0x53be:dū # 厾 0x53bf:xiàn,xuán # 县 0x53c0:zhuān # 叀 0x53c1:sān # 叁 0x53c2:cān,shēn,cēn,sān # 参 0x53c3:cān,shēn,cēn,sān # 參 0x53c4:cān,shēn,cēn,sān # 叄 0x53c5:cān,shēn,cēn,sān # 叅 0x53c6:ài # 叆 0x53c7:dài # 叇 0x53c8:yòu # 又 0x53c9:chā,chá,chǎ # 叉 0x53ca:jí # 及 0x53cb:yǒu # 友 0x53cc:shuāng # 双 0x53cd:fǎn # 反 0x53ce:shōu # 収 0x53cf:guái # 叏 0x53d0:bá # 叐 0x53d1:fā,fà # 发 0x53d2:ruò # 叒 0x53d3:lì # 叓 0x53d4:shū # 叔 0x53d5:zhuó,yǐ,lì,jué # 叕 0x53d6:qǔ # 取 0x53d7:shòu # 受 0x53d8:biàn # 变 0x53d9:xù # 叙 0x53da:jiǎ # 叚 0x53db:pàn # 叛 0x53dc:sǒu # 叜 0x53dd:jí # 叝 0x53de:wèi,yù # 叞 0x53df:sǒu # 叟 0x53e0:dié # 叠 0x53e1:ruì # 叡 0x53e2:cóng # 叢 0x53e3:kǒu # 口 0x53e4:gǔ # 古 0x53e5:jù,gōu # 句 0x53e6:lìng # 另 0x53e7:guǎ # 叧 0x53e8:tāo,dāo # 叨 0x53e9:kòu # 叩 0x53ea:zhī,zhǐ # 只 0x53eb:jiào # 叫 0x53ec:zhào,shào # 召 0x53ed:bā # 叭 0x53ee:dīng # 叮 0x53ef:kě,kè # 可 0x53f0:tái,tāi # 台 0x53f1:chì # 叱 0x53f2:shǐ # 史 0x53f3:yòu # 右 0x53f4:qiú # 叴 0x53f5:pǒ # 叵 0x53f6:yè,xié # 叶 0x53f7:hào,háo # 号 0x53f8:sī # 司 0x53f9:tàn # 叹 0x53fa:chǐ # 叺 0x53fb:lè # 叻 0x53fc:diāo # 叼 0x53fd:jī # 叽 0x53ff:hōng,hóng # 叿 0x5400:miē # 吀 0x5401:xū,yù # 吁 0x5402:máng # 吂 0x5403:chī # 吃 0x5404:gè,gě # 各 0x5405:xuān,sòng # 吅 0x5406:yāo # 吆 0x5407:zǐ # 吇 0x5408:hé,gě # 合 0x5409:jí # 吉 0x540a:diào # 吊 0x540b:dòu,cùn # 吋 0x540c:tóng,tòng # 同 0x540d:míng # 名 0x540e:hòu # 后 0x540f:lì # 吏 0x5410:tǔ,tù # 吐 0x5411:xiàng # 向 0x5412:zhà,zhā # 吒 0x5413:xià,hè # 吓 0x5414:yē # 吔 0x5415:lǚ # 吕 0x5416:yā,ā # 吖 0x5417:má,mǎ,ma # 吗 0x5418:ǒu # 吘 0x5419:huō # 吙 0x541a:yī # 吚 0x541b:jūn # 君 0x541c:chǒu # 吜 0x541d:lìn # 吝 0x541e:tūn # 吞 0x541f:yín # 吟 0x5420:fèi # 吠 0x5421:pǐ,bǐ # 吡 0x5422:qìn # 吢 0x5423:qìn # 吣 0x5424:jiè,gè # 吤 0x5425:bù # 吥 0x5426:fǒu,pǐ # 否 0x5427:bā,ba # 吧 0x5428:dūn # 吨 0x5429:fēn # 吩 0x542a:é,huā # 吪 0x542b:hán # 含 0x542c:tīng # 听 0x542d:háng,kēng # 吭 0x542e:shǔn # 吮 0x542f:qǐ # 启 0x5430:hóng # 吰 0x5431:zhī,zī # 吱 0x5432:yǐn,shěn # 吲 0x5433:wú # 吳 0x5434:wú # 吴 0x5435:chǎo,chāo # 吵 0x5436:nà,nè # 吶 0x5437:xuè,chuò,jué # 吷 0x5438:xī # 吸 0x5439:chuī # 吹 0x543a:dōu,rú # 吺 0x543b:wěn # 吻 0x543c:hǒu # 吼 0x543d:hǒu,hōng,ōu # 吽 0x543e:wú,yù # 吾 0x543f:gào # 吿 0x5440:yā,ya # 呀 0x5441:jùn # 呁 0x5442:lǚ # 呂 0x5443:è # 呃 0x5444:gé # 呄 0x5445:wěn # 呅 0x5446:dāi # 呆 0x5447:qǐ # 呇 0x5448:chéng # 呈 0x5449:wú # 呉 0x544a:gào # 告 0x544b:fū # 呋 0x544c:jiào # 呌 0x544d:hōng # 呍 0x544e:chǐ # 呎 0x544f:shēng # 呏 0x5450:nà,nè # 呐 0x5451:tūn,tiān # 呑 0x5452:fǔ,ḿ # 呒 0x5453:yì # 呓 0x5454:dāi,tǎi # 呔 0x5455:ǒu,ōu,òu # 呕 0x5456:lì # 呖 0x5457:bei,bài # 呗 0x5458:yuán,yún,yùn # 员 0x5459:wāi,hé,wǒ,wā,guǎ,guō # 呙 0x545b:qiāng,qiàng # 呛 0x545c:wū # 呜 0x545d:è # 呝 0x545e:shī # 呞 0x545f:juǎn # 呟 0x5460:pěn # 呠 0x5461:mǐn,wěn # 呡 0x5462:ne,ní # 呢 0x5464:líng # 呤 0x5465:rán # 呥 0x5466:yōu # 呦 0x5467:dǐ # 呧 0x5468:zhōu # 周 0x5469:shì # 呩 0x546a:zhòu # 呪 0x546b:tiè,chè # 呫 0x546c:xì # 呬 0x546d:yì # 呭 0x546e:qì,zhī # 呮 0x546f:píng # 呯 0x5470:zǐ,cī # 呰 0x5471:guā,gū,guǎ # 呱 0x5472:zī,cī # 呲 0x5473:wèi # 味 0x5474:xǔ,hǒu,gòu # 呴 0x5475:hē,a,kē # 呵 0x5476:náo # 呶 0x5477:xiā,gā # 呷 0x5478:pēi # 呸 0x5479:yì # 呹 0x547a:xiāo,háo # 呺 0x547b:shēn # 呻 0x547c:hū # 呼 0x547d:mìng # 命 0x547e:dá,dàn # 呾 0x547f:qū # 呿 0x5480:jǔ,zuǐ # 咀 0x5482:zā # 咂 0x5483:tuō # 咃 0x5484:duō # 咄 0x5485:pǒu # 咅 0x5486:páo # 咆 0x5487:bì # 咇 0x5488:fú # 咈 0x5489:yǎng # 咉 0x548a:hé,hè # 咊 0x548b:zǎ,zé,zhā # 咋 0x548c:hé,hè,huó,huò,hú # 和 0x548d:hāi # 咍 0x548e:jiù # 咎 0x548f:yǒng # 咏 0x5490:fù # 咐 0x5491:dā # 咑 0x5492:zhòu # 咒 0x5493:wǎ # 咓 0x5494:kǎ # 咔 0x5495:gū # 咕 0x5496:kā,gā # 咖 0x5497:zuo # 咗 0x5498:bù # 咘 0x5499:lóng # 咙 0x549a:dōng # 咚 0x549b:níng # 咛 0x549d:sī # 咝 0x549e:xiàn,xián # 咞 0x549f:huò # 咟 0x54a0:qì # 咠 0x54a1:èr # 咡 0x54a2:è # 咢 0x54a3:guāng # 咣 0x54a4:zhà # 咤 0x54a5:dié,xī # 咥 0x54a6:yí # 咦 0x54a7:liě,liē,lié,lie # 咧 0x54a8:zī # 咨 0x54a9:miē # 咩 0x54aa:mī # 咪 0x54ab:zhǐ # 咫 0x54ac:yǎo # 咬 0x54ad:jī,xī,qià # 咭 0x54ae:zhòu # 咮 0x54af:lo,kǎ,luò,gē # 咯 0x54b0:shù,xún # 咰 0x54b1:zán,zá,zǎ # 咱 0x54b2:xiào # 咲 0x54b3:ké,hāi # 咳 0x54b4:huī # 咴 0x54b5:kuā # 咵 0x54b6:huài,shì # 咶 0x54b7:táo # 咷 0x54b8:xián # 咸 0x54b9:è,àn # 咹 0x54ba:xuǎn,xuān # 咺 0x54bb:xiū # 咻 0x54bc:wāi,hé,wǒ,wā,guǎ,guō # 咼 0x54bd:yān,yàn,yè # 咽 0x54be:lǎo # 咾 0x54bf:yī # 咿 0x54c0:āi # 哀 0x54c1:pǐn # 品 0x54c2:shěn # 哂 0x54c3:tóng # 哃 0x54c4:hōng,hǒng,hòng # 哄 0x54c5:xiōng # 哅 0x54c6:duō # 哆 0x54c7:wā,wa # 哇 0x54c8:hā,hǎ,hà # 哈 0x54c9:zāi # 哉 0x54ca:yòu # 哊 0x54cb:diè,dì # 哋 0x54cc:pài # 哌 0x54cd:xiǎng # 响 0x54ce:āi # 哎 0x54cf:gén,hěn # 哏 0x54d0:kuāng # 哐 0x54d1:yǎ,yā # 哑 0x54d2:dā # 哒 0x54d3:xiāo # 哓 0x54d4:bì # 哔 0x54d5:yuě,huì # 哕 0x54d7:huá,huā # 哗 0x54d9:kuài # 哙 0x54da:duǒ # 哚 0x54dc:jì,jiē,zhāi # 哜 0x54dd:nóng # 哝 0x54de:mōu # 哞 0x54df:yō,yo # 哟 0x54e0:hào # 哠 0x54e1:yuán,yún,yùn # 員 0x54e2:lòng # 哢 0x54e3:pǒu # 哣 0x54e4:máng # 哤 0x54e5:gē # 哥 0x54e6:ó,ò,é # 哦 0x54e7:chī # 哧 0x54e8:shào # 哨 0x54e9:li,lǐ,lī # 哩 0x54ea:nǎ,něi,na,né # 哪 0x54eb:zú # 哫 0x54ec:hè # 哬 0x54ed:kū # 哭 0x54ee:xiào # 哮 0x54ef:xiàn # 哯 0x54f0:láo # 哰 0x54f1:pò,bā,bō # 哱 0x54f2:zhé # 哲 0x54f3:zhā # 哳 0x54f4:liàng,láng # 哴 0x54f5:bā # 哵 0x54f6:miē # 哶 0x54f7:liè,lǜ # 哷 0x54f8:suī # 哸 0x54f9:fú # 哹 0x54fa:bǔ # 哺 0x54fb:hān # 哻 0x54fc:hēng,hng # 哼 0x54fd:gěng # 哽 0x54fe:chuò,yuè # 哾 0x54ff:gě,jiā # 哿 0x5500:yòu # 唀 0x5501:yàn # 唁 0x5502:gū # 唂 0x5503:gū # 唃 0x5504:bei,bài # 唄 0x5505:hán,hàn # 唅 0x5506:suō # 唆 0x5507:chún # 唇 0x5508:yì # 唈 0x5509:āi,ài # 唉 0x550a:jiá,qiǎn # 唊 0x550b:tǔ,tù # 唋 0x550c:dàn,xián,yán # 唌 0x550d:wǎn # 唍 0x550e:lì # 唎 0x550f:xī # 唏 0x5510:táng # 唐 0x5511:zuò # 唑 0x5512:qiú # 唒 0x5513:chē # 唓 0x5514:wù,wú,ńg,ń # 唔 0x5515:zào # 唕 0x5516:yǎ # 唖 0x5517:dōu # 唗 0x5518:qǐ # 唘 0x5519:dí # 唙 0x551a:qìn # 唚 0x551b:mà # 唛 0x551d:gòng,hǒng,gǒng # 唝 0x551e:dóu # 唞 0x5520:lào,láo # 唠 0x5521:liǎng # 唡 0x5522:suǒ # 唢 0x5523:zào # 唣 0x5524:huàn # 唤 0x5526:shā # 唦 0x5527:jī # 唧 0x5528:zǔ # 唨 0x5529:wō,wěi # 唩 0x552a:fěng # 唪 0x552b:jìn,yín # 唫 0x552c:hǔ,xià # 唬 0x552d:qì # 唭 0x552e:shòu # 售 0x552f:wéi # 唯 0x5530:shuā # 唰 0x5531:chàng # 唱 0x5532:ér,wā # 唲 0x5533:lì # 唳 0x5534:qiàng # 唴 0x5535:ǎn # 唵 0x5536:jiè,zé,jí # 唶 0x5537:yō # 唷 0x5538:niàn # 唸 0x5539:yū # 唹 0x553a:tiǎn # 唺 0x553b:lài # 唻 0x553c:shà # 唼 0x553d:xī # 唽 0x553e:tuò # 唾 0x553f:hū # 唿 0x5540:ái # 啀 0x5541:zhōu,zhāo,tiào # 啁 0x5542:gòu # 啂 0x5543:kěn # 啃 0x5544:zhuó # 啄 0x5545:zhuó,zhào # 啅 0x5546:shāng # 商 0x5547:dí # 啇 0x5548:hèng # 啈 0x5549:lán,lín # 啉 0x554a:ā,á,ǎ,à,a # 啊 0x554b:cǎi # 啋 0x554c:qiāng # 啌 0x554d:zhūn,tūn,xiāng,duǐ # 啍 0x554e:wǔ # 啎 0x554f:wèn # 問 0x5550:cuì,qi # 啐 0x5551:shà,jié,dié,tì # 啑 0x5552:gǔ # 啒 0x5553:qǐ # 啓 0x5554:qǐ # 啔 0x5555:táo # 啕 0x5556:dàn # 啖 0x5557:dàn # 啗 0x5558:yuē,wā # 啘 0x5559:zǐ,cǐ # 啙 0x555a:bǐ,tú # 啚 0x555b:cuì # 啛 0x555c:chuò,chuài # 啜 0x555d:hé # 啝 0x555e:yǎ,yā # 啞 0x555f:qǐ # 啟 0x5560:zhé # 啠 0x5561:fēi # 啡 0x5562:liǎng # 啢 0x5563:xián # 啣 0x5564:pí # 啤 0x5565:shá # 啥 0x5566:lā,la # 啦 0x5567:zé # 啧 0x5568:qíng,yīng # 啨 0x5569:guà # 啩 0x556a:pā # 啪 0x556b:zhě,shì # 啫 0x556c:sè # 啬 0x556d:zhuàn # 啭 0x556e:niè # 啮 0x556f:guō # 啯 0x5570:luō,luó,luo # 啰 0x5571:yán # 啱 0x5572:dī # 啲 0x5573:quán # 啳 0x5574:tān,chǎn,tuō # 啴 0x5575:bo # 啵 0x5576:dìng # 啶 0x5577:lāng # 啷 0x5578:xiào # 啸 0x557a:táng # 啺 0x557b:chì # 啻 0x557c:tí # 啼 0x557d:ān,án # 啽 0x557e:jiū # 啾 0x557f:dàn # 啿 0x5580:kā # 喀 0x5581:yóng,yú # 喁 0x5582:wèi # 喂 0x5583:nán # 喃 0x5584:shàn # 善 0x5585:yù # 喅 0x5586:zhé # 喆 0x5587:lǎ # 喇 0x5588:jiē # 喈 0x5589:hóu # 喉 0x558a:hǎn # 喊 0x558b:dié,zhá # 喋 0x558c:zhōu # 喌 0x558d:chái # 喍 0x558e:wāi # 喎 0x558f:nuò,rě # 喏 0x5590:huò,guó,xù # 喐 0x5591:yīn # 喑 0x5592:zán,zá,zǎ # 喒 0x5593:yāo # 喓 0x5594:ō,wō # 喔 0x5595:miǎn # 喕 0x5596:hú # 喖 0x5597:yǔn # 喗 0x5598:chuǎn # 喘 0x5599:huì # 喙 0x559a:huàn # 喚 0x559b:huàn,yuán,xuǎn,hé # 喛 0x559c:xǐ # 喜 0x559d:hē,hè,yè # 喝 0x559e:jī # 喞 0x559f:kuì # 喟 0x55a0:zhǒng,chuáng # 喠 0x55a1:wéi,wèi # 喡 0x55a2:shà # 喢 0x55a3:xǔ # 喣 0x55a4:huáng # 喤 0x55a5:duó,zhà # 喥 0x55a6:yán # 喦 0x55a7:xuān # 喧 0x55a8:liàng # 喨 0x55a9:yù # 喩 0x55aa:sāng,sàng # 喪 0x55ab:chī # 喫 0x55ac:qiáo,jiāo # 喬 0x55ad:yàn # 喭 0x55ae:dān,shàn,chán # 單 0x55af:pèn,bēn # 喯 0x55b0:cān,sūn,qī # 喰 0x55b1:lí # 喱 0x55b2:yō,yo # 喲 0x55b3:zhā,chā # 喳 0x55b4:wēi # 喴 0x55b5:miāo # 喵 0x55b6:yíng # 営 0x55b7:pēn,pèn # 喷 0x55b9:kuí # 喹 0x55ba:xí # 喺 0x55bb:yù # 喻 0x55bc:jiē # 喼 0x55bd:lóu,lou # 喽 0x55be:kù # 喾 0x55bf:zào,qiāo # 喿 0x55c0:hù # 嗀 0x55c1:tí # 嗁 0x55c2:yáo # 嗂 0x55c3:hè,xiāo,xiào,hù # 嗃 0x55c4:shà,á # 嗄 0x55c5:xiù # 嗅 0x55c6:qiāng,qiàng # 嗆 0x55c7:sè # 嗇 0x55c8:yōng # 嗈 0x55c9:sù # 嗉 0x55ca:gòng,hǒng,gǒng # 嗊 0x55cb:xié # 嗋 0x55cc:yì,ài # 嗌 0x55cd:suō # 嗍 0x55ce:má,mǎ,ma # 嗎 0x55cf:chā # 嗏 0x55d0:hài # 嗐 0x55d1:kē,kè # 嗑 0x55d2:tà,dā # 嗒 0x55d3:sǎng # 嗓 0x55d4:chēn # 嗔 0x55d5:rù # 嗕 0x55d6:sōu # 嗖 0x55d7:wā,gǔ # 嗗 0x55d8:jī # 嗘 0x55d9:bēng,pǎng # 嗙 0x55da:wū # 嗚 0x55db:xián,qiàn,qiè # 嗛 0x55dc:shì # 嗜 0x55dd:gé # 嗝 0x55de:zī # 嗞 0x55df:jiē # 嗟 0x55e0:lào # 嗠 0x55e1:wēng # 嗡 0x55e2:wà # 嗢 0x55e3:sì # 嗣 0x55e4:chī # 嗤 0x55e5:háo # 嗥 0x55e6:suō # 嗦 0x55e8:hāi,hēi # 嗨 0x55e9:suǒ # 嗩 0x55ea:qín # 嗪 0x55eb:niè # 嗫 0x55ec:hē # 嗬 0x55ee:sǎi # 嗮 0x55f0:gě # 嗰 0x55f1:ná # 嗱 0x55f2:diǎ # 嗲 0x55f3:ǎi,ài,āi # 嗳 0x55f5:tōng # 嗵 0x55f6:bì # 嗶 0x55f7:áo # 嗷 0x55f8:áo # 嗸 0x55f9:lián # 嗹 0x55fa:zuī,suī # 嗺 0x55fb:zhē,zhè,zhù,zhe # 嗻 0x55fc:mò # 嗼 0x55fd:sòu # 嗽 0x55fe:sǒu # 嗾 0x55ff:tǎn # 嗿 0x5600:dí # 嘀 0x5601:qī # 嘁 0x5602:jiào # 嘂 0x5603:chōng # 嘃 0x5604:jiào,dǎo # 嘄 0x5605:kǎi,gě # 嘅 0x5606:tàn # 嘆 0x5607:shān,càn # 嘇 0x5608:cáo # 嘈 0x5609:jiā # 嘉 0x560a:ái # 嘊 0x560b:xiào # 嘋 0x560c:piāo # 嘌 0x560d:lóu,lou # 嘍 0x560e:gā,gá,gǎ # 嘎 0x560f:gǔ,jiǎ # 嘏 0x5610:xiāo,jiāo # 嘐 0x5611:hū # 嘑 0x5612:huì # 嘒 0x5613:guō # 嘓 0x5614:ǒu,ōu,òu # 嘔 0x5615:xiān # 嘕 0x5616:zé # 嘖 0x5617:cháng # 嘗 0x5618:xū,shī # 嘘 0x5619:pó # 嘙 0x561a:dē,dēi # 嘚 0x561b:má,ma # 嘛 0x561c:mà # 嘜 0x561d:hú # 嘝 0x561e:lei,lē # 嘞 0x561f:dū # 嘟 0x5620:gā,gá,gǎ # 嘠 0x5621:tāng # 嘡 0x5622:yě # 嘢 0x5623:bēng # 嘣 0x5624:yīng # 嘤 0x5626:jiào # 嘦 0x5627:mì # 嘧 0x5628:xiào # 嘨 0x5629:huá,huā # 嘩 0x562a:mǎi # 嘪 0x562b:rán # 嘫 0x562c:zuō,chuài # 嘬 0x562d:pēng # 嘭 0x562e:lào,láo # 嘮 0x562f:xiào # 嘯 0x5630:jī # 嘰 0x5631:zhǔ # 嘱 0x5632:cháo,zhāo # 嘲 0x5633:kuì # 嘳 0x5634:zuǐ # 嘴 0x5635:xiāo # 嘵 0x5636:sī # 嘶 0x5637:háo # 嘷 0x5638:fǔ,ḿ # 嘸 0x5639:liáo # 嘹 0x563a:qiáo,qiào # 嘺 0x563b:xī # 嘻 0x563c:chù,xù,shòu # 嘼 0x563d:tān,chǎn # 嘽 0x563e:dàn,tán # 嘾 0x563f:hēi,mò # 嘿 0x5640:xùn # 噀 0x5641:ě # 噁 0x5642:zūn # 噂 0x5643:fān,bo # 噃 0x5644:chī # 噄 0x5645:huī # 噅 0x5646:zǎn # 噆 0x5647:chuáng # 噇 0x5648:cù,zā,hé # 噈 0x5649:dàn # 噉 0x564a:jué # 噊 0x564b:tūn,kuò # 噋 0x564c:cēng,chēng # 噌 0x564d:jiào # 噍 0x564e:yē # 噎 0x564f:xī # 噏 0x5650:qì # 噐 0x5651:háo # 噑 0x5652:lián # 噒 0x5653:xū,shī # 噓 0x5654:dēng # 噔 0x5655:huī # 噕 0x5656:yín # 噖 0x5657:pū # 噗 0x5658:juē # 噘 0x5659:qín # 噙 0x565a:xún # 噚 0x565b:niè # 噛 0x565c:lū # 噜 0x565d:sī # 噝 0x565e:yǎn # 噞 0x565f:yīng # 噟 0x5660:dā # 噠 0x5661:zhān,dān # 噡 0x5662:ō # 噢 0x5663:zhòu,zhuó # 噣 0x5664:jìn # 噤 0x5665:nóng # 噥 0x5666:yuě,huì # 噦 0x5667:xiè # 噧 0x5668:qì # 器 0x5669:è # 噩 0x566a:zào # 噪 0x566b:yī # 噫 0x566c:shì # 噬 0x566d:jiào,qiào,chī # 噭 0x566e:yuàn # 噮 0x566f:ǎi,ài,āi # 噯 0x5670:yōng,yǒng # 噰 0x5671:jué,xué # 噱 0x5672:kuài # 噲 0x5673:yǔ # 噳 0x5674:pēn,pèn # 噴 0x5675:dào # 噵 0x5676:gá # 噶 0x5677:xīn,hěn,hèn # 噷 0x5678:dūn # 噸 0x5679:dāng # 噹 0x567b:sāi # 噻 0x567c:pī # 噼 0x567d:pǐ # 噽 0x567e:yīn # 噾 0x567f:zuǐ # 噿 0x5680:níng # 嚀 0x5681:dí # 嚁 0x5682:làn # 嚂 0x5683:tà # 嚃 0x5684:huò,ǒ # 嚄 0x5685:rú # 嚅 0x5686:hāo # 嚆 0x5687:hè,xià # 嚇 0x5688:yàn # 嚈 0x5689:duō # 嚉 0x568a:xiù,pì # 嚊 0x568b:zhōu,chóu # 嚋 0x568c:jì,jiē,zhāi # 嚌 0x568d:jìn # 嚍 0x568e:háo # 嚎 0x568f:tì # 嚏 0x5690:cháng # 嚐 0x5693:cā,chā # 嚓 0x5694:tì # 嚔 0x5695:lū # 嚕 0x5696:huì # 嚖 0x5697:bó,pào,bào # 嚗 0x5698:yōu # 嚘 0x5699:niè # 嚙 0x569a:yín # 嚚 0x569b:hù # 嚛 0x569c:mèi,me,mò # 嚜 0x569d:hōng # 嚝 0x569e:zhé # 嚞 0x569f:lí # 嚟 0x56a0:liú # 嚠 0x56a2:náng # 嚢 0x56a3:xiāo,áo # 嚣 0x56a4:mō # 嚤 0x56a5:yàn # 嚥 0x56a6:lì # 嚦 0x56a7:lú # 嚧 0x56a8:lóng # 嚨 0x56a9:pó # 嚩 0x56aa:dàn # 嚪 0x56ab:chèn # 嚫 0x56ac:pín # 嚬 0x56ad:pǐ # 嚭 0x56ae:xiàng # 嚮 0x56af:huò # 嚯 0x56b0:mè # 嚰 0x56b1:xī # 嚱 0x56b2:duǒ # 嚲 0x56b3:kù # 嚳 0x56b4:yán # 嚴 0x56b5:chán # 嚵 0x56b6:yīng # 嚶 0x56b7:rǎng,rāng # 嚷 0x56b8:diǎn,dím # 嚸 0x56b9:lá # 嚹 0x56ba:tà # 嚺 0x56bb:xiāo # 嚻 0x56bc:jiáo,jué,jiào # 嚼 0x56bd:chuò # 嚽 0x56be:huàn,huān # 嚾 0x56bf:huò # 嚿 0x56c0:zhuàn # 囀 0x56c1:niè # 囁 0x56c2:xiāo # 囂 0x56c3:zá,cà # 囃 0x56c4:lí # 囄 0x56c5:chǎn # 囅 0x56c6:chài # 囆 0x56c7:lì # 囇 0x56c8:yì # 囈 0x56c9:luō,luó,luo # 囉 0x56ca:náng,nāng # 囊 0x56cb:zá,zàn,cān # 囋 0x56cc:sū # 囌 0x56cd:xǐ # 囍 0x56cf:jiān # 囏 0x56d0:yàn,zá,niè # 囐 0x56d1:zhǔ # 囑 0x56d2:lán # 囒 0x56d3:niè # 囓 0x56d4:nāng # 囔 0x56d7:wéi,guó # 囗 0x56d8:huí # 囘 0x56d9:yīn # 囙 0x56da:qiú # 囚 0x56db:sì # 四 0x56dc:nín # 囜 0x56dd:jiǎn,nān # 囝 0x56de:huí # 回 0x56df:xìn # 囟 0x56e0:yīn # 因 0x56e1:nān # 囡 0x56e2:tuán # 团 0x56e3:tuán # 団 0x56e4:dùn,tún # 囤 0x56e5:kàng # 囥 0x56e6:yuān # 囦 0x56e7:jiǒng # 囧 0x56e8:piān # 囨 0x56e9:yún # 囩 0x56ea:cōng # 囪 0x56eb:hú # 囫 0x56ec:huí # 囬 0x56ed:yuán # 园 0x56ee:é # 囮 0x56ef:guó # 囯 0x56f0:kùn # 困 0x56f1:cōng # 囱 0x56f2:wéi,tōng # 囲 0x56f3:tú # 図 0x56f4:wéi # 围 0x56f5:lún # 囵 0x56f6:guó # 囶 0x56f7:qūn # 囷 0x56f8:rì # 囸 0x56f9:líng # 囹 0x56fa:gù # 固 0x56fb:guó # 囻 0x56fc:tāi # 囼 0x56fd:guó # 国 0x56fe:tú # 图 0x56ff:yòu # 囿 0x5700:guó # 圀 0x5701:yín # 圁 0x5702:hùn # 圂 0x5703:pǔ # 圃 0x5704:yǔ # 圄 0x5705:hán # 圅 0x5706:yuán # 圆 0x5707:lún # 圇 0x5708:quān,juàn,juān # 圈 0x5709:yǔ # 圉 0x570a:qīng # 圊 0x570b:guó # 國 0x570c:chuán,chuí # 圌 0x570d:wéi # 圍 0x570e:yuán # 圎 0x570f:quān,juàn,juān # 圏 0x5710:kū # 圐 0x5711:pǔ # 圑 0x5712:yuán # 園 0x5713:yuán # 圓 0x5714:yà # 圔 0x5716:tú # 圖 0x5717:tú # 圗 0x5718:tuán # 團 0x5719:lüè # 圙 0x571a:huì # 圚 0x571b:yì # 圛 0x571c:huán,yuán # 圜 0x571d:luán # 圝 0x571e:luán # 圞 0x571f:tǔ # 土 0x5720:yà # 圠 0x5721:tǔ # 圡 0x5722:tǐng # 圢 0x5723:shèng # 圣 0x5724:pú # 圤 0x5725:lù # 圥 0x5727:yā # 圧 0x5728:zài # 在 0x5729:wéi,xū # 圩 0x572a:gē # 圪 0x572b:yù,zhūn # 圫 0x572c:wū # 圬 0x572d:guī # 圭 0x572e:pǐ # 圮 0x572f:yí # 圯 0x5730:dì,de # 地 0x5731:qiān,sú # 圱 0x5732:qiān # 圲 0x5733:zhèn # 圳 0x5734:zhuó # 圴 0x5735:dàng # 圵 0x5736:qià # 圶 0x5739:kuàng # 圹 0x573a:cháng,chǎng # 场 0x573b:qí,yín # 圻 0x573c:niè # 圼 0x573d:mò # 圽 0x573e:jī # 圾 0x573f:jiá # 圿 0x5740:zhǐ # 址 0x5741:zhǐ,zhì # 坁 0x5742:bǎn # 坂 0x5743:xūn # 坃 0x5744:yì # 坄 0x5745:qǐn # 坅 0x5746:méi,fén # 坆 0x5747:jūn # 均 0x5748:rǒng,kēng # 坈 0x5749:tún,dùn # 坉 0x574a:fāng,fáng # 坊 0x574b:bèn,fèn # 坋 0x574c:bèn # 坌 0x574d:tān # 坍 0x574e:kǎn # 坎 0x574f:huài,pēi,pī,péi # 坏 0x5750:zuò # 坐 0x5751:kēng # 坑 0x5752:bì # 坒 0x5753:jǐng # 坓 0x5754:dì,làn # 坔 0x5755:jīng # 坕 0x5756:jì # 坖 0x5757:kuài # 块 0x5758:dǐ # 坘 0x5759:jīng # 坙 0x575a:jiān # 坚 0x575b:tán # 坛 0x575c:lì # 坜 0x575d:bà # 坝 0x575e:wù # 坞 0x575f:fén # 坟 0x5760:zhuì # 坠 0x5761:pō # 坡 0x5762:pǎn,bàn # 坢 0x5763:táng # 坣 0x5764:kūn # 坤 0x5765:qū # 坥 0x5766:tǎn # 坦 0x5767:zhǐ # 坧 0x5768:tuó # 坨 0x5769:gān # 坩 0x576a:píng # 坪 0x576b:diàn # 坫 0x576c:guà # 坬 0x576d:ní # 坭 0x576e:tái # 坮 0x576f:pī # 坯 0x5770:jiōng # 坰 0x5771:yǎng # 坱 0x5772:fó # 坲 0x5773:ào # 坳 0x5774:lù # 坴 0x5775:qiū # 坵 0x5776:mù,mǔ # 坶 0x5777:kē,kě # 坷 0x5778:gòu # 坸 0x5779:xuè # 坹 0x577a:fá # 坺 0x577b:dǐ,chí # 坻 0x577c:chè # 坼 0x577d:líng # 坽 0x577e:zhù # 坾 0x577f:fù # 坿 0x5780:hū # 垀 0x5781:zhì # 垁 0x5782:chuí # 垂 0x5783:lā # 垃 0x5784:lǒng # 垄 0x5785:lǒng # 垅 0x5786:lú # 垆 0x5787:ào # 垇 0x5789:páo # 垉 0x578b:xíng # 型 0x578c:dòng,tóng # 垌 0x578d:jì # 垍 0x578e:hè # 垎 0x578f:lǜ # 垏 0x5790:cí # 垐 0x5791:chǐ # 垑 0x5792:lěi # 垒 0x5793:gāi # 垓 0x5794:yīn # 垔 0x5795:hòu # 垕 0x5796:duī # 垖 0x5797:zhào # 垗 0x5798:fú # 垘 0x5799:guāng # 垙 0x579a:yáo # 垚 0x579b:duǒ,duò # 垛 0x579c:duǒ,duò # 垜 0x579d:guǐ # 垝 0x579e:chá # 垞 0x579f:yáng # 垟 0x57a0:yín # 垠 0x57a1:fá # 垡 0x57a2:gòu # 垢 0x57a3:yuán # 垣 0x57a4:dié # 垤 0x57a5:xié # 垥 0x57a6:kěn # 垦 0x57a7:shǎng # 垧 0x57a8:shǒu # 垨 0x57a9:è # 垩 0x57ab:diàn # 垫 0x57ac:hóng # 垬 0x57ad:yā # 垭 0x57ae:kuǎ # 垮 0x57b1:dàng # 垱 0x57b2:kǎi # 垲 0x57b4:nǎo # 垴 0x57b5:ǎn # 垵 0x57b6:xīng # 垶 0x57b7:xiàn # 垷 0x57b8:yuàn,huán # 垸 0x57b9:bāng # 垹 0x57ba:póu,fú # 垺 0x57bb:bà # 垻 0x57bc:yì # 垼 0x57bd:yìn # 垽 0x57be:hàn # 垾 0x57bf:xù # 垿 0x57c0:chuí # 埀 0x57c1:cén # 埁 0x57c2:gěng # 埂 0x57c3:āi # 埃 0x57c4:běng,fēng # 埄 0x57c5:dì,fáng # 埅 0x57c6:què,jué # 埆 0x57c7:yǒng # 埇 0x57c8:jùn # 埈 0x57c9:xiá,jiā # 埉 0x57ca:dì # 埊 0x57cb:mái,mán # 埋 0x57cc:làng # 埌 0x57cd:juǎn # 埍 0x57ce:chéng # 城 0x57cf:yán,shān # 埏 0x57d0:qín,jīn # 埐 0x57d1:zhé # 埑 0x57d2:liè # 埒 0x57d3:liè # 埓 0x57d4:pǔ,bù # 埔 0x57d5:chéng # 埕 0x57d7:bù # 埗 0x57d8:shí # 埘 0x57d9:xūn # 埙 0x57da:guō # 埚 0x57db:jiōng # 埛 0x57dc:yě # 埜 0x57dd:niàn # 埝 0x57de:dī # 埞 0x57df:yù # 域 0x57e0:bù # 埠 0x57e1:yà # 埡 0x57e2:quán # 埢 0x57e3:suì,sù # 埣 0x57e4:pí,pì # 埤 0x57e5:qīng,zhēng # 埥 0x57e6:wǎn,wān # 埦 0x57e7:jù # 埧 0x57e8:lǔn # 埨 0x57e9:zhēng,chéng # 埩 0x57ea:kōng # 埪 0x57eb:chǒng,shǎng # 埫 0x57ec:dōng # 埬 0x57ed:dài # 埭 0x57ee:tán,tàn # 埮 0x57ef:ǎn # 埯 0x57f0:cǎi,cài # 埰 0x57f1:chù,tòu # 埱 0x57f2:běng # 埲 0x57f3:xiàn,kǎn # 埳 0x57f4:zhí # 埴 0x57f5:duǒ # 埵 0x57f6:yì,shì # 埶 0x57f7:zhí # 執 0x57f8:yì # 埸 0x57f9:péi # 培 0x57fa:jī # 基 0x57fb:zhǔn # 埻 0x57fc:qí # 埼 0x57fd:sào,sǎo # 埽 0x57fe:jù # 埾 0x57ff:ní # 埿 0x5800:kū # 堀 0x5801:kè # 堁 0x5802:táng # 堂 0x5803:kūn # 堃 0x5804:nì # 堄 0x5805:jiān # 堅 0x5806:duī # 堆 0x5807:jīn # 堇 0x5808:gāng # 堈 0x5809:yù # 堉 0x580a:è # 堊 0x580b:péng,bèng # 堋 0x580c:gù # 堌 0x580d:tù # 堍 0x580e:lèng # 堎 0x5810:yá # 堐 0x5811:qiàn,zàn,jiàn # 堑 0x5813:àn # 堓 0x5815:duò,huī # 堕 0x5816:nǎo # 堖 0x5817:tū # 堗 0x5818:chéng # 堘 0x5819:yīn # 堙 0x581a:huán # 堚 0x581b:bì # 堛 0x581c:liàn # 堜 0x581d:guō # 堝 0x581e:dié # 堞 0x581f:zhuàn # 堟 0x5820:hòu # 堠 0x5821:bǎo,bǔ,pù # 堡 0x5822:bǎo # 堢 0x5823:yú # 堣 0x5824:dī # 堤 0x5825:máo,móu,wǔ # 堥 0x5826:jiē # 堦 0x5827:ruán # 堧 0x5828:è,ài,yè # 堨 0x5829:gèng # 堩 0x582a:kān # 堪 0x582b:zōng # 堫 0x582c:yú # 堬 0x582d:huáng # 堭 0x582e:è # 堮 0x582f:yáo # 堯 0x5830:yàn # 堰 0x5831:bào # 報 0x5832:jí # 堲 0x5833:méi # 堳 0x5834:cháng,chǎng # 場 0x5835:dǔ # 堵 0x5836:tuó # 堶 0x5837:yìn # 堷 0x5838:féng # 堸 0x5839:zhòng # 堹 0x583a:jiè # 堺 0x583b:jīn # 堻 0x583c:fēng # 堼 0x583d:gāng # 堽 0x583e:chuǎn,chūn # 堾 0x583f:jiǎn # 堿 0x5842:jiǎng # 塂 0x5843:huāng # 塃 0x5844:léng # 塄 0x5845:duàn # 塅 0x5847:xuān # 塇 0x5848:jì,xì # 塈 0x5849:jí # 塉 0x584a:kuài # 塊 0x584b:yíng # 塋 0x584c:tā # 塌 0x584d:chéng # 塍 0x584e:yǒng # 塎 0x584f:kǎi # 塏 0x5850:sù # 塐 0x5851:sù # 塑 0x5852:shí # 塒 0x5853:mì # 塓 0x5854:tǎ # 塔 0x5855:wěng # 塕 0x5856:chéng # 塖 0x5857:tú # 塗 0x5858:táng # 塘 0x5859:què # 塙 0x585a:zhǒng # 塚 0x585b:lì # 塛 0x585c:péng # 塜 0x585d:bàng # 塝 0x585e:sāi,sài,sè # 塞 0x585f:zàng # 塟 0x5860:duī # 塠 0x5861:tián # 塡 0x5862:wù # 塢 0x5863:zhèng # 塣 0x5864:xūn # 塤 0x5865:gé # 塥 0x5866:zhèn # 塦 0x5867:ài # 塧 0x5868:gōng # 塨 0x5869:yán # 塩 0x586a:xiàn # 塪 0x586b:tián,zhèn # 填 0x586c:yuán # 塬 0x586d:wēn # 塭 0x586e:xiè # 塮 0x586f:liù # 塯 0x5871:lǎng # 塱 0x5872:cháng,chǎng # 塲 0x5873:péng # 塳 0x5874:bèng # 塴 0x5875:chén # 塵 0x5876:lù # 塶 0x5877:lǔ # 塷 0x5878:ōu,qiū # 塸 0x5879:qiàn,zàn,jiàn # 塹 0x587a:méi # 塺 0x587b:mò # 塻 0x587c:zhuān,tuán # 塼 0x587d:shuǎng # 塽 0x587e:shú # 塾 0x587f:lǒu # 塿 0x5880:chí # 墀 0x5881:màn # 墁 0x5882:biāo # 墂 0x5883:jìng # 境 0x5884:qī # 墄 0x5885:shù # 墅 0x5886:zhì,dì # 墆 0x5887:zhàng # 墇 0x5888:kàn # 墈 0x5889:yōng # 墉 0x588a:diàn # 墊 0x588b:chěn # 墋 0x588c:zhǐ,zhuó # 墌 0x588d:xì # 墍 0x588e:guō # 墎 0x588f:qiǎng # 墏 0x5890:jìn # 墐 0x5891:dì # 墑 0x5892:shāng # 墒 0x5893:mù # 墓 0x5894:cuī # 墔 0x5895:yàn # 墕 0x5896:tǎ # 墖 0x5897:zēng # 増 0x5898:qián # 墘 0x5899:qiáng # 墙 0x589a:liáng # 墚 0x589c:zhuì # 墜 0x589d:qiāo # 墝 0x589e:zēng # 增 0x589f:xū # 墟 0x58a0:shàn # 墠 0x58a1:shàn # 墡 0x58a2:fá # 墢 0x58a3:pú # 墣 0x58a4:kuài,tuí # 墤 0x58a5:tuǎn,dǒng # 墥 0x58a6:fán # 墦 0x58a7:qiáo,què # 墧 0x58a8:mò # 墨 0x58a9:dūn # 墩 0x58aa:dūn # 墪 0x58ab:zūn,dūn # 墫 0x58ac:dì # 墬 0x58ad:shèng # 墭 0x58ae:duò,huī # 墮 0x58af:duò # 墯 0x58b0:tán # 墰 0x58b1:dèng # 墱 0x58b2:wú # 墲 0x58b3:fén # 墳 0x58b4:huáng # 墴 0x58b5:tán # 墵 0x58b6:dā # 墶 0x58b7:yè # 墷 0x58ba:ào # 墺 0x58bb:qiáng # 墻 0x58bc:jī # 墼 0x58bd:qiāo,áo # 墽 0x58be:kěn # 墾 0x58bf:yì,tú # 墿 0x58c0:pí # 壀 0x58c1:bì # 壁 0x58c2:diàn # 壂 0x58c3:jiāng # 壃 0x58c4:yě # 壄 0x58c5:yōng # 壅 0x58c6:xué,bó,jué # 壆 0x58c7:tán # 壇 0x58c8:lǎn # 壈 0x58c9:jù # 壉 0x58ca:huài # 壊 0x58cb:dàng # 壋 0x58cc:rǎng # 壌 0x58cd:qiàn # 壍 0x58ce:xūn # 壎 0x58cf:xiàn,làn # 壏 0x58d0:xǐ # 壐 0x58d1:hè # 壑 0x58d2:ài # 壒 0x58d3:yā,yà # 壓 0x58d4:dǎo # 壔 0x58d5:háo # 壕 0x58d6:ruán # 壖 0x58d8:lěi # 壘 0x58d9:kuàng # 壙 0x58da:lú # 壚 0x58db:yán # 壛 0x58dc:tán # 壜 0x58dd:wéi # 壝 0x58de:huài # 壞 0x58df:lǒng # 壟 0x58e0:lǒng # 壠 0x58e1:ruǐ # 壡 0x58e2:lì # 壢 0x58e3:lín # 壣 0x58e4:rǎng # 壤 0x58e6:xūn # 壦 0x58e7:yán # 壧 0x58e8:lěi # 壨 0x58e9:bà # 壩 0x58eb:shì # 士 0x58ec:rén # 壬 0x58ee:zhuàng # 壮 0x58ef:zhuàng # 壯 0x58f0:shēng # 声 0x58f1:yī # 壱 0x58f2:mài # 売 0x58f3:ké,qiào # 壳 0x58f4:zhù # 壴 0x58f5:zhuàng # 壵 0x58f6:hú # 壶 0x58f7:hú # 壷 0x58f8:kǔn # 壸 0x58f9:yī # 壹 0x58fa:hú # 壺 0x58fb:xù # 壻 0x58fc:kǔn # 壼 0x58fd:shòu # 壽 0x58fe:mǎng # 壾 0x58ff:cún,dun # 壿 0x5900:shòu # 夀 0x5901:yī # 夁 0x5902:zhǐ,zhōng # 夂 0x5903:gǔ,yíng # 夃 0x5904:chǔ,chù # 处 0x5905:jiàng,xiáng # 夅 0x5906:féng,fēng,páng # 夆 0x5907:bèi # 备 0x5909:biàn # 変 0x590a:suī # 夊 0x590b:qūn # 夋 0x590c:líng # 夌 0x590d:fù # 复 0x590e:cuò # 夎 0x590f:xià # 夏 0x5910:xiòng,xuàn # 夐 0x5912:náo # 夒 0x5913:xià # 夓 0x5914:kuí # 夔 0x5915:xī # 夕 0x5916:wài # 外 0x5917:yuàn,wǎn,wān,yuān # 夗 0x5918:mǎo,wǎn # 夘 0x5919:sù # 夙 0x591a:duō # 多 0x591b:duō # 夛 0x591c:yè # 夜 0x591d:qíng # 夝 0x591f:gòu # 够 0x5920:gòu # 夠 0x5921:qì # 夡 0x5922:mèng # 夢 0x5923:mèng # 夣 0x5924:yín # 夤 0x5925:huǒ # 夥 0x5926:chěn # 夦 0x5927:dà,dài,tài # 大 0x5928:cè # 夨 0x5929:tiān # 天 0x592a:tài # 太 0x592b:fū,fú # 夫 0x592c:guài # 夬 0x592d:yāo # 夭 0x592e:yāng # 央 0x592f:hāng,bèn # 夯 0x5930:gǎo # 夰 0x5931:shī # 失 0x5932:tāo,běn # 夲 0x5933:tài # 夳 0x5934:tóu,tou # 头 0x5935:yǎn,tāo # 夵 0x5936:bǐ # 夶 0x5937:yí # 夷 0x5938:kuā,kuà # 夸 0x5939:jiā,jiá,gā # 夹 0x593a:duó # 夺 0x593c:kuǎng # 夼 0x593d:yǔn # 夽 0x593e:jiā,jiá,gā,xiá # 夾 0x593f:bā # 夿 0x5940:ēn # 奀 0x5941:lián # 奁 0x5942:huàn # 奂 0x5943:dī,tì # 奃 0x5944:yǎn,yān # 奄 0x5945:pào # 奅 0x5946:juàn # 奆 0x5947:qí,jī # 奇 0x5948:nài # 奈 0x5949:fèng # 奉 0x594a:xié # 奊 0x594b:fèn # 奋 0x594c:diǎn # 奌 0x594e:kuí # 奎 0x594f:zòu # 奏 0x5950:huàn # 奐 0x5951:qì,qiè,xiè # 契 0x5952:kāi # 奒 0x5953:shē,chǐ,zhà # 奓 0x5954:bēn,bèn # 奔 0x5955:yì # 奕 0x5956:jiǎng # 奖 0x5957:tào # 套 0x5958:zàng,zhuǎng # 奘 0x5959:běn # 奙 0x595a:xī # 奚 0x595b:huǎng # 奛 0x595c:fěi # 奜 0x595d:diāo # 奝 0x595e:xùn,zhuì # 奞 0x595f:bēng # 奟 0x5960:diàn # 奠 0x5961:ào # 奡 0x5962:shē # 奢 0x5963:wěng # 奣 0x5964:pò,hǎ,tǎi # 奤 0x5965:ào,yù # 奥 0x5966:wù # 奦 0x5967:ào,yù # 奧 0x5968:jiǎng # 奨 0x5969:lián # 奩 0x596a:duó # 奪 0x596b:yūn # 奫 0x596c:jiǎng # 奬 0x596d:shì # 奭 0x596e:fèn # 奮 0x596f:huò # 奯 0x5970:bì # 奰 0x5971:luán # 奱 0x5972:duǒ,chě # 奲 0x5973:nǚ,rǔ # 女 0x5974:nú # 奴 0x5975:dǐng,dīng,tiǎn # 奵 0x5976:nǎi # 奶 0x5977:qiān # 奷 0x5978:jiān # 奸 0x5979:tā,jiě # 她 0x597a:jiǔ # 奺 0x597b:nuán # 奻 0x597c:chà # 奼 0x597d:hǎo,hào # 好 0x597e:xiān # 奾 0x597f:fàn # 奿 0x5980:jǐ # 妀 0x5981:shuò # 妁 0x5982:rú # 如 0x5983:fēi,pèi # 妃 0x5984:wàng # 妄 0x5985:hóng # 妅 0x5986:zhuāng # 妆 0x5987:fù # 妇 0x5988:mā # 妈 0x5989:dān # 妉 0x598a:rèn # 妊 0x598b:fū,yōu # 妋 0x598c:jìng # 妌 0x598d:yán # 妍 0x598e:hài,jiè # 妎 0x598f:wèn # 妏 0x5990:zhōng # 妐 0x5991:pā # 妑 0x5992:dù # 妒 0x5993:jì # 妓 0x5994:kēng,háng # 妔 0x5995:zhòng # 妕 0x5996:yāo # 妖 0x5997:jìn # 妗 0x5998:yún # 妘 0x5999:miào # 妙 0x599a:fǒu,pēi,pī # 妚 0x599c:yuè,jué # 妜 0x599d:zhuāng # 妝 0x599e:niū,hào # 妞 0x599f:yàn # 妟 0x59a0:nà,nàn # 妠 0x59a1:xīn # 妡 0x59a2:fén # 妢 0x59a3:bǐ # 妣 0x59a4:yú # 妤 0x59a5:tuǒ # 妥 0x59a6:fēng # 妦 0x59a7:wàn,yuán # 妧 0x59a8:fáng # 妨 0x59a9:wǔ # 妩 0x59aa:yù # 妪 0x59ab:guī # 妫 0x59ac:dù # 妬 0x59ad:bá # 妭 0x59ae:nī # 妮 0x59af:zhóu # 妯 0x59b0:zhuó # 妰 0x59b1:zhāo # 妱 0x59b2:dá # 妲 0x59b3:nǐ,nǎi # 妳 0x59b4:yuàn # 妴 0x59b5:tǒu # 妵 0x59b6:xián,xuán,xù # 妶 0x59b7:zhí,yì # 妷 0x59b8:ē # 妸 0x59b9:mèi # 妹 0x59ba:mò # 妺 0x59bb:qī,qì # 妻 0x59bc:bì # 妼 0x59bd:shēn # 妽 0x59be:qiè # 妾 0x59bf:ē # 妿 0x59c0:hé # 姀 0x59c1:xǔ,xū # 姁 0x59c2:fá # 姂 0x59c3:zhēng # 姃 0x59c4:mín # 姄 0x59c5:bàn # 姅 0x59c6:mǔ # 姆 0x59c7:fū,fú # 姇 0x59c8:líng # 姈 0x59c9:zǐ # 姉 0x59ca:zǐ # 姊 0x59cb:shǐ # 始 0x59cc:rǎn # 姌 0x59cd:shān,shàn # 姍 0x59ce:yāng # 姎 0x59cf:mán # 姏 0x59d0:jiě # 姐 0x59d1:gū # 姑 0x59d2:sì # 姒 0x59d3:xìng # 姓 0x59d4:wěi,wēi # 委 0x59d5:zī # 姕 0x59d6:jù # 姖 0x59d7:shān,shàn # 姗 0x59d8:pīn # 姘 0x59d9:rèn # 姙 0x59da:yáo # 姚 0x59db:dòng # 姛 0x59dc:jiāng # 姜 0x59dd:shū # 姝 0x59de:jí # 姞 0x59df:gāi # 姟 0x59e0:xiàng # 姠 0x59e1:huá,huó # 姡 0x59e2:juān # 姢 0x59e3:jiāo,xiáo # 姣 0x59e4:gòu,dù # 姤 0x59e5:mǔ,lǎo # 姥 0x59e6:jiān # 姦 0x59e7:jiān # 姧 0x59e8:yí # 姨 0x59e9:nián,niàn # 姩 0x59ea:zhí # 姪 0x59eb:zhěn # 姫 0x59ec:jī # 姬 0x59ed:xiàn # 姭 0x59ee:héng # 姮 0x59ef:guāng # 姯 0x59f0:jūn,xún # 姰 0x59f1:kuā,hù # 姱 0x59f2:yàn # 姲 0x59f3:mǐng # 姳 0x59f4:liè # 姴 0x59f5:pèi # 姵 0x59f6:è,yà # 姶 0x59f7:yòu # 姷 0x59f8:yán # 姸 0x59f9:chà # 姹 0x59fa:shēn,xiān # 姺 0x59fb:yīn # 姻 0x59fc:shí # 姼 0x59fd:guǐ # 姽 0x59fe:quán # 姾 0x59ff:zī # 姿 0x5a00:sōng # 娀 0x5a01:wēi # 威 0x5a02:hóng # 娂 0x5a03:wá # 娃 0x5a04:lóu # 娄 0x5a05:yà # 娅 0x5a06:ráo,rǎo # 娆 0x5a07:jiāo # 娇 0x5a08:luán # 娈 0x5a09:pīng # 娉 0x5a0a:xiàn # 娊 0x5a0b:shào,shāo # 娋 0x5a0c:lǐ # 娌 0x5a0d:chéng,shèng # 娍 0x5a0e:xiē # 娎 0x5a0f:máng # 娏 0x5a11:suō # 娑 0x5a12:wǔ,mǔ # 娒 0x5a13:wěi # 娓 0x5a14:kè # 娔 0x5a15:chuò,lài # 娕 0x5a16:chuò # 娖 0x5a17:tǐng # 娗 0x5a18:niáng # 娘 0x5a19:xíng # 娙 0x5a1a:nán # 娚 0x5a1b:yú # 娛 0x5a1c:nà,nuó # 娜 0x5a1d:pōu,bǐ # 娝 0x5a1e:něi,suī # 娞 0x5a1f:juān # 娟 0x5a20:shēn # 娠 0x5a21:zhì # 娡 0x5a22:hán # 娢 0x5a23:dì # 娣 0x5a24:zhuāng # 娤 0x5a25:é # 娥 0x5a26:pín # 娦 0x5a27:tuì # 娧 0x5a28:mǎn,xiàn # 娨 0x5a29:miǎn # 娩 0x5a2a:wú,wù,yú # 娪 0x5a2b:yán # 娫 0x5a2c:wǔ # 娬 0x5a2d:xī,āi # 娭 0x5a2e:yán # 娮 0x5a2f:yú # 娯 0x5a30:sì # 娰 0x5a31:yú # 娱 0x5a32:wā # 娲 0x5a34:xián # 娴 0x5a35:jū # 娵 0x5a36:qǔ # 娶 0x5a37:zhuì,shuì # 娷 0x5a38:qī # 娸 0x5a39:xián # 娹 0x5a3a:zhuó # 娺 0x5a3b:dōng,dòng # 娻 0x5a3c:chāng # 娼 0x5a3d:lù # 娽 0x5a3e:ǎi,ái,è # 娾 0x5a3f:ē,ě # 娿 0x5a40:ē # 婀 0x5a41:lóu # 婁 0x5a42:mián # 婂 0x5a43:cóng # 婃 0x5a44:pǒu,péi,bù # 婄 0x5a45:jú # 婅 0x5a46:pó # 婆 0x5a47:cǎi # 婇 0x5a48:líng # 婈 0x5a49:wǎn # 婉 0x5a4a:biǎo # 婊 0x5a4b:xiāo # 婋 0x5a4c:shū # 婌 0x5a4d:qǐ # 婍 0x5a4e:huī # 婎 0x5a4f:fù,fàn # 婏 0x5a50:wǒ # 婐 0x5a51:wǒ # 婑 0x5a52:tán # 婒 0x5a53:fēi # 婓 0x5a55:jié # 婕 0x5a56:tiān # 婖 0x5a57:ní,nǐ # 婗 0x5a58:quán,juàn # 婘 0x5a59:jìng # 婙 0x5a5a:hūn # 婚 0x5a5b:jīng # 婛 0x5a5c:qiān,jǐn # 婜 0x5a5d:diàn # 婝 0x5a5e:xìng # 婞 0x5a5f:hù # 婟 0x5a60:wān,wà # 婠 0x5a61:lái,lài # 婡 0x5a62:bì # 婢 0x5a63:yīn # 婣 0x5a64:zhōu,chōu # 婤 0x5a65:chuò,nào # 婥 0x5a66:fù # 婦 0x5a67:jìng # 婧 0x5a68:lún # 婨 0x5a69:nüè # 婩 0x5a6a:lán # 婪 0x5a6b:hùn,kūn # 婫 0x5a6c:yín # 婬 0x5a6d:yà # 婭 0x5a6f:lì # 婯 0x5a70:diǎn # 婰 0x5a71:xián # 婱 0x5a73:huà # 婳 0x5a74:yīng # 婴 0x5a75:chán # 婵 0x5a76:shěn # 婶 0x5a77:tíng # 婷 0x5a78:dàng,yáng # 婸 0x5a79:yǎo # 婹 0x5a7a:wù # 婺 0x5a7b:nàn # 婻 0x5a7c:ruò,chuò # 婼 0x5a7d:jiǎ # 婽 0x5a7e:tōu,yú # 婾 0x5a7f:xù # 婿 0x5a80:yù,yú # 媀 0x5a81:wéi,wěi # 媁 0x5a82:dì,tí # 媂 0x5a83:róu # 媃 0x5a84:měi # 媄 0x5a85:dān # 媅 0x5a86:ruǎn,nèn # 媆 0x5a87:qīn # 媇 0x5a89:wò # 媉 0x5a8a:qián # 媊 0x5a8b:chūn # 媋 0x5a8c:miáo # 媌 0x5a8d:fù # 媍 0x5a8e:jiě # 媎 0x5a8f:duān # 媏 0x5a90:yí,pèi # 媐 0x5a91:zhòng # 媑 0x5a92:méi # 媒 0x5a93:huáng # 媓 0x5a94:mián,miǎn # 媔 0x5a95:ān # 媕 0x5a96:yīng # 媖 0x5a97:xuān # 媗 0x5a99:wēi # 媙 0x5a9a:mèi # 媚 0x5a9b:yuàn,yuán # 媛 0x5a9c:zhēng # 媜 0x5a9d:qiū # 媝 0x5a9e:tí # 媞 0x5a9f:xiè # 媟 0x5aa0:tuó,duò # 媠 0x5aa1:liàn # 媡 0x5aa2:mào # 媢 0x5aa3:rǎn # 媣 0x5aa4:sī # 媤 0x5aa5:piān # 媥 0x5aa6:wèi # 媦 0x5aa7:wā # 媧 0x5aa8:cù # 媨 0x5aa9:hú # 媩 0x5aaa:ǎo # 媪 0x5aad:xū # 媭 0x5aae:tōu,yú # 媮 0x5aaf:guī # 媯 0x5ab0:chú,zòu # 媰 0x5ab1:yáo # 媱 0x5ab2:pì # 媲 0x5ab3:xí # 媳 0x5ab4:yuán # 媴 0x5ab5:yìng # 媵 0x5ab6:róng # 媶 0x5ab7:rù # 媷 0x5ab8:chī # 媸 0x5ab9:liú # 媹 0x5aba:měi # 媺 0x5abb:pán # 媻 0x5abc:ǎo # 媼 0x5abd:mā # 媽 0x5abe:gòu # 媾 0x5abf:kuì # 媿 0x5ac0:qín,shēn # 嫀 0x5ac1:jià # 嫁 0x5ac2:sǎo # 嫂 0x5ac3:zhēn,zhěn # 嫃 0x5ac4:yuán # 嫄 0x5ac5:jiē,suǒ # 嫅 0x5ac6:róng # 嫆 0x5ac7:míng,mǐng # 嫇 0x5ac8:yīng # 嫈 0x5ac9:jí # 嫉 0x5aca:sù # 嫊 0x5acb:niǎo # 嫋 0x5acc:xián # 嫌 0x5acd:tāo # 嫍 0x5ace:páng # 嫎 0x5acf:láng # 嫏 0x5ad0:nǎo # 嫐 0x5ad1:biáo # 嫑 0x5ad2:ài # 嫒 0x5ad3:pì # 嫓 0x5ad4:pín # 嫔 0x5ad5:yì # 嫕 0x5ad6:piáo,piāo # 嫖 0x5ad7:yù # 嫗 0x5ad8:léi # 嫘 0x5ad9:xuán # 嫙 0x5ada:màn # 嫚 0x5adb:yī # 嫛 0x5adc:zhāng # 嫜 0x5add:kāng # 嫝 0x5ade:yōng # 嫞 0x5adf:nì # 嫟 0x5ae0:lí # 嫠 0x5ae1:dí # 嫡 0x5ae2:guī # 嫢 0x5ae3:yān # 嫣 0x5ae4:jǐn,jìn # 嫤 0x5ae5:zhuān # 嫥 0x5ae6:cháng # 嫦 0x5ae7:zé # 嫧 0x5ae8:hān,nǎn # 嫨 0x5ae9:nèn # 嫩 0x5aea:lào # 嫪 0x5aeb:mó # 嫫 0x5aec:zhē # 嫬 0x5aed:hù # 嫭 0x5aee:hù # 嫮 0x5aef:ào # 嫯 0x5af0:nèn # 嫰 0x5af1:qiáng # 嫱 0x5af3:piè # 嫳 0x5af4:gū # 嫴 0x5af5:wǔ # 嫵 0x5af6:qiáo # 嫶 0x5af7:tuǒ # 嫷 0x5af8:zhǎn # 嫸 0x5af9:miáo # 嫹 0x5afa:xián # 嫺 0x5afb:xián # 嫻 0x5afc:mò # 嫼 0x5afd:liáo # 嫽 0x5afe:lián # 嫾 0x5aff:huà # 嫿 0x5b00:guī # 嬀 0x5b01:dēng # 嬁 0x5b02:zhí # 嬂 0x5b03:xū # 嬃 0x5b05:huà # 嬅 0x5b06:xī # 嬆 0x5b07:kuì # 嬇 0x5b08:ráo,rǎo # 嬈 0x5b09:xī # 嬉 0x5b0a:yàn # 嬊 0x5b0b:chán # 嬋 0x5b0c:jiāo # 嬌 0x5b0d:měi # 嬍 0x5b0e:fàn # 嬎 0x5b0f:fān # 嬏 0x5b10:xiān,yǎn,jìn # 嬐 0x5b11:yì # 嬑 0x5b12:huì # 嬒 0x5b13:jiào # 嬓 0x5b14:fù # 嬔 0x5b15:shì # 嬕 0x5b16:bì # 嬖 0x5b17:shàn # 嬗 0x5b18:suì # 嬘 0x5b19:qiáng # 嬙 0x5b1a:liǎn # 嬚 0x5b1b:huán,xuān,qióng # 嬛 0x5b1d:niǎo # 嬝 0x5b1e:dǒng # 嬞 0x5b1f:yǐ # 嬟 0x5b20:cān # 嬠 0x5b21:ài # 嬡 0x5b22:niáng # 嬢 0x5b23:níng # 嬣 0x5b24:mó # 嬤 0x5b25:tiǎo # 嬥 0x5b26:chóu # 嬦 0x5b27:jìn # 嬧 0x5b28:cí # 嬨 0x5b29:yú # 嬩 0x5b2a:pín # 嬪 0x5b2c:rú # 嬬 0x5b2d:nǎi # 嬭 0x5b2e:yān,yàn # 嬮 0x5b2f:tái # 嬯 0x5b30:yīng # 嬰 0x5b31:qiàn # 嬱 0x5b32:niǎo # 嬲 0x5b34:yíng # 嬴 0x5b35:mián # 嬵 0x5b37:mó # 嬷 0x5b38:shěn # 嬸 0x5b39:xìng # 嬹 0x5b3a:nì # 嬺 0x5b3b:dú # 嬻 0x5b3c:liǔ # 嬼 0x5b3d:yuān # 嬽 0x5b3e:lǎn # 嬾 0x5b3f:yàn # 嬿 0x5b40:shuāng # 孀 0x5b41:líng # 孁 0x5b42:jiǎo # 孂 0x5b43:niáng # 孃 0x5b44:lǎn # 孄 0x5b45:xiān,qiān # 孅 0x5b46:yīng # 孆 0x5b47:shuāng # 孇 0x5b48:xié,huī # 孈 0x5b49:huān,quán # 孉 0x5b4a:mǐ # 孊 0x5b4b:lí,lì # 孋 0x5b4c:luán # 孌 0x5b4d:yǎn # 孍 0x5b4e:zhú,chuò # 孎 0x5b4f:lǎn # 孏 0x5b50:zǐ # 子 0x5b51:jié # 孑 0x5b52:jué # 孒 0x5b53:jué # 孓 0x5b54:kǒng # 孔 0x5b55:yùn # 孕 0x5b56:zī,mā # 孖 0x5b57:zì # 字 0x5b58:cún # 存 0x5b59:sūn,xùn # 孙 0x5b5a:fú # 孚 0x5b5b:bèi,bó # 孛 0x5b5c:zī # 孜 0x5b5d:xiào # 孝 0x5b5e:xìn # 孞 0x5b5f:mèng # 孟 0x5b60:sì # 孠 0x5b61:tāi # 孡 0x5b62:bāo # 孢 0x5b63:jì # 季 0x5b64:gū # 孤 0x5b65:nú # 孥 0x5b66:xué # 学 0x5b68:zhuǎn # 孨 0x5b69:hái # 孩 0x5b6a:luán # 孪 0x5b6b:sūn,xùn # 孫 0x5b6c:nāo # 孬 0x5b6d:miē # 孭 0x5b6e:cóng # 孮 0x5b6f:qiān # 孯 0x5b70:shú # 孰 0x5b71:chán,càn # 孱 0x5b72:yā # 孲 0x5b73:zī # 孳 0x5b74:nǐ # 孴 0x5b75:fū # 孵 0x5b76:zī # 孶 0x5b77:lí # 孷 0x5b78:xué # 學 0x5b79:bò # 孹 0x5b7a:rú # 孺 0x5b7b:nái # 孻 0x5b7c:niè # 孼 0x5b7d:niè # 孽 0x5b7e:yīng # 孾 0x5b7f:luán # 孿 0x5b80:mián # 宀 0x5b81:níng,nìng,zhù # 宁 0x5b82:rǒng # 宂 0x5b83:tā # 它 0x5b84:guǐ # 宄 0x5b85:zhái # 宅 0x5b86:qióng # 宆 0x5b87:yǔ # 宇 0x5b88:shǒu # 守 0x5b89:ān # 安 0x5b8a:tū,jiā # 宊 0x5b8b:sòng # 宋 0x5b8c:wán # 完 0x5b8d:ròu # 宍 0x5b8e:yǎo # 宎 0x5b8f:hóng # 宏 0x5b90:yí # 宐 0x5b91:jǐng # 宑 0x5b92:zhūn # 宒 0x5b93:mì,fú # 宓 0x5b94:zhǔ # 宔 0x5b95:dàng # 宕 0x5b96:hóng # 宖 0x5b97:zōng # 宗 0x5b98:guān # 官 0x5b99:zhòu # 宙 0x5b9a:dìng # 定 0x5b9b:wǎn,yuān # 宛 0x5b9c:yí # 宜 0x5b9d:bǎo # 宝 0x5b9e:shí # 实 0x5b9f:shí # 実 0x5ba0:chǒng # 宠 0x5ba1:shěn # 审 0x5ba2:kè # 客 0x5ba3:xuān # 宣 0x5ba4:shì # 室 0x5ba5:yòu # 宥 0x5ba6:huàn # 宦 0x5ba7:yí # 宧 0x5ba8:tiǎo # 宨 0x5ba9:shǐ # 宩 0x5baa:xiàn # 宪 0x5bab:gōng # 宫 0x5bac:chéng # 宬 0x5bad:qún # 宭 0x5bae:gōng # 宮 0x5baf:xiāo # 宯 0x5bb0:zǎi # 宰 0x5bb1:zhà # 宱 0x5bb2:bǎo,shí # 宲 0x5bb3:hài # 害 0x5bb4:yàn # 宴 0x5bb5:xiāo # 宵 0x5bb6:jiā,jia,jie # 家 0x5bb7:shěn # 宷 0x5bb8:chén # 宸 0x5bb9:róng # 容 0x5bba:huāng,huǎng # 宺 0x5bbb:mì # 宻 0x5bbc:kòu # 宼 0x5bbd:kuān # 宽 0x5bbe:bīn # 宾 0x5bbf:sù,xiǔ,xiù # 宿 0x5bc0:cǎi,cài # 寀 0x5bc1:zǎn # 寁 0x5bc2:jì # 寂 0x5bc3:yuān # 寃 0x5bc4:jì # 寄 0x5bc5:yín # 寅 0x5bc6:mì # 密 0x5bc7:kòu # 寇 0x5bc8:qīng # 寈 0x5bc9:hè # 寉 0x5bca:zhēn # 寊 0x5bcb:jiàn # 寋 0x5bcc:fù # 富 0x5bcd:níng,nìng # 寍 0x5bce:bǐng,bìng # 寎 0x5bcf:huán # 寏 0x5bd0:mèi # 寐 0x5bd1:qǐn # 寑 0x5bd2:hán # 寒 0x5bd3:yù # 寓 0x5bd4:shí # 寔 0x5bd5:níng,nìng # 寕 0x5bd6:jìn,qǐn # 寖 0x5bd7:níng,nìng # 寗 0x5bd8:zhì # 寘 0x5bd9:yǔ # 寙 0x5bda:bǎo # 寚 0x5bdb:kuān # 寛 0x5bdc:níng,nìng # 寜 0x5bdd:qǐn # 寝 0x5bde:mò # 寞 0x5bdf:chá # 察 0x5be0:jù,lóu # 寠 0x5be1:guǎ # 寡 0x5be2:qǐn # 寢 0x5be3:hū # 寣 0x5be4:wù # 寤 0x5be5:liáo # 寥 0x5be6:shí # 實 0x5be7:níng,nìng # 寧 0x5be8:zhài # 寨 0x5be9:shěn # 審 0x5bea:wěi # 寪 0x5beb:xiě,xiè # 寫 0x5bec:kuān # 寬 0x5bed:huì # 寭 0x5bee:liáo # 寮 0x5bef:jùn # 寯 0x5bf0:huán # 寰 0x5bf1:yì # 寱 0x5bf2:yí # 寲 0x5bf3:bǎo # 寳 0x5bf4:qīn,qìn # 寴 0x5bf5:chǒng # 寵 0x5bf6:bǎo # 寶 0x5bf7:fēng # 寷 0x5bf8:cùn # 寸 0x5bf9:duì # 对 0x5bfa:sì # 寺 0x5bfb:xún # 寻 0x5bfc:dǎo # 导 0x5bfd:lüè,luó # 寽 0x5bfe:duì # 対 0x5bff:shòu # 寿 0x5c00:pǒ # 尀 0x5c01:fēng # 封 0x5c02:zhuān # 専 0x5c03:fū # 尃 0x5c04:shè,yè,yì # 射 0x5c05:kēi,kè # 尅 0x5c06:jiāng,jiàng # 将 0x5c07:jiāng,jiàng # 將 0x5c08:zhuān # 專 0x5c09:wèi,yù # 尉 0x5c0a:zūn # 尊 0x5c0b:xún # 尋 0x5c0c:shù,zhù # 尌 0x5c0d:duì # 對 0x5c0e:dǎo # 導 0x5c0f:xiǎo # 小 0x5c10:jié,jí # 尐 0x5c11:shǎo,shào # 少 0x5c12:ěr # 尒 0x5c13:ěr # 尓 0x5c14:ěr # 尔 0x5c15:gǎ # 尕 0x5c16:jiān # 尖 0x5c17:shú # 尗 0x5c18:chén # 尘 0x5c19:shàng # 尙 0x5c1a:shàng # 尚 0x5c1c:gá # 尜 0x5c1d:cháng # 尝 0x5c1e:liáo # 尞 0x5c1f:xiǎn # 尟 0x5c20:xiǎn # 尠 0x5c22:yóu # 尢 0x5c23:wāng # 尣 0x5c24:yóu # 尤 0x5c25:liào # 尥 0x5c26:liào # 尦 0x5c27:yáo # 尧 0x5c28:lóng,máng,méng,páng # 尨 0x5c29:wāng # 尩 0x5c2a:wāng # 尪 0x5c2b:wāng # 尫 0x5c2c:gà # 尬 0x5c2d:yáo # 尭 0x5c2e:duò # 尮 0x5c2f:kuì,kuǐ # 尯 0x5c30:zhǒng # 尰 0x5c31:jiù # 就 0x5c32:gān # 尲 0x5c33:gǔ # 尳 0x5c34:gān # 尴 0x5c35:tuí # 尵 0x5c36:gān # 尶 0x5c37:gān # 尷 0x5c38:shī # 尸 0x5c39:yǐn # 尹 0x5c3a:chǐ,chě # 尺 0x5c3b:kāo # 尻 0x5c3c:ní # 尼 0x5c3d:jìn,jǐn # 尽 0x5c3e:wěi,yǐ # 尾 0x5c3f:niào,suī # 尿 0x5c40:jú # 局 0x5c41:pì # 屁 0x5c42:céng # 层 0x5c43:xì # 屃 0x5c44:bī # 屄 0x5c45:jū # 居 0x5c46:jiè # 屆 0x5c47:tián # 屇 0x5c48:qū # 屈 0x5c49:tì # 屉 0x5c4a:jiè # 届 0x5c4b:wū # 屋 0x5c4c:diǎo # 屌 0x5c4d:shī # 屍 0x5c4e:shǐ # 屎 0x5c4f:píng,bǐng # 屏 0x5c50:jī # 屐 0x5c51:xiè # 屑 0x5c52:zhěn # 屒 0x5c53:xì # 屓 0x5c54:ní # 屔 0x5c55:zhǎn # 展 0x5c56:xī # 屖 0x5c58:mǎn # 屘 0x5c59:ē # 屙 0x5c5a:lòu # 屚 0x5c5b:pǐng,bǐng # 屛 0x5c5c:tì # 屜 0x5c5d:fèi # 屝 0x5c5e:shǔ,zhǔ # 属 0x5c5f:xiè,tì # 屟 0x5c60:tú # 屠 0x5c61:lǚ # 屡 0x5c62:lǚ # 屢 0x5c63:xǐ # 屣 0x5c64:céng # 層 0x5c65:lǚ # 履 0x5c66:jù # 屦 0x5c67:xiè # 屧 0x5c68:jù # 屨 0x5c69:juē # 屩 0x5c6a:liáo # 屪 0x5c6b:juē # 屫 0x5c6c:shǔ,zhǔ # 屬 0x5c6d:xì # 屭 0x5c6e:chè,cǎo # 屮 0x5c6f:tún,zhūn # 屯 0x5c70:nì,jǐ # 屰 0x5c71:shān # 山 0x5c73:xiān # 屳 0x5c74:lì # 屴 0x5c75:àn # 屵 0x5c78:hóng,lóng # 屸 0x5c79:yì # 屹 0x5c7a:qǐ # 屺 0x5c7b:rèn # 屻 0x5c7c:wù # 屼 0x5c7d:hàn,àn # 屽 0x5c7e:shēn # 屾 0x5c7f:yǔ # 屿 0x5c80:chū # 岀 0x5c81:suì # 岁 0x5c82:qǐ,kǎi # 岂 0x5c84:yuè # 岄 0x5c85:bǎn # 岅 0x5c86:yǎo # 岆 0x5c87:áng # 岇 0x5c88:yá # 岈 0x5c89:wù # 岉 0x5c8a:jié # 岊 0x5c8b:è # 岋 0x5c8c:jí # 岌 0x5c8d:qiān # 岍 0x5c8e:fén # 岎 0x5c8f:wán # 岏 0x5c90:qí # 岐 0x5c91:cén # 岑 0x5c92:qián # 岒 0x5c93:qí # 岓 0x5c94:chà # 岔 0x5c95:jiè # 岕 0x5c96:qū # 岖 0x5c97:gǎng # 岗 0x5c98:xiàn # 岘 0x5c99:ào # 岙 0x5c9a:lán # 岚 0x5c9b:dǎo # 岛 0x5c9c:bā # 岜 0x5c9d:zuò # 岝 0x5c9e:zuò # 岞 0x5c9f:yǎng # 岟 0x5ca0:jù # 岠 0x5ca1:gāng # 岡 0x5ca2:kě # 岢 0x5ca3:gǒu # 岣 0x5ca4:xuè # 岤 0x5ca5:pō # 岥 0x5ca6:lì # 岦 0x5ca7:tiáo # 岧 0x5ca8:jū,jǔ # 岨 0x5ca9:yán # 岩 0x5caa:fú # 岪 0x5cab:xiù # 岫 0x5cac:jiǎ # 岬 0x5cad:lǐng,líng # 岭 0x5cae:tuó # 岮 0x5caf:pī # 岯 0x5cb0:ào # 岰 0x5cb1:dài # 岱 0x5cb2:kuàng # 岲 0x5cb3:yuè # 岳 0x5cb4:qū # 岴 0x5cb5:hù # 岵 0x5cb6:pò # 岶 0x5cb7:mín # 岷 0x5cb8:àn # 岸 0x5cb9:tiáo # 岹 0x5cba:lǐng,líng # 岺 0x5cbb:dī # 岻 0x5cbd:dōng # 岽 0x5cbf:kuī # 岿 0x5cc0:xiù # 峀 0x5cc1:mǎo # 峁 0x5cc2:tóng # 峂 0x5cc3:xué # 峃 0x5cc4:yì # 峄 0x5cc6:hé # 峆 0x5cc7:kè,bā # 峇 0x5cc8:luò # 峈 0x5cc9:é # 峉 0x5cca:fù,niè # 峊 0x5ccb:xún # 峋 0x5ccc:dié # 峌 0x5ccd:lù # 峍 0x5cce:ěn # 峎 0x5ccf:ér # 峏 0x5cd0:gāi # 峐 0x5cd1:quán # 峑 0x5cd2:tóng,dòng # 峒 0x5cd3:yí # 峓 0x5cd4:mǔ # 峔 0x5cd5:shí # 峕 0x5cd6:ān # 峖 0x5cd7:wéi # 峗 0x5cd8:huán # 峘 0x5cd9:zhì,shì # 峙 0x5cda:mì # 峚 0x5cdb:lǐ # 峛 0x5cdc:fǎ,jī # 峜 0x5cdd:tóng # 峝 0x5cde:wéi # 峞 0x5cdf:yòu # 峟 0x5ce1:xiá # 峡 0x5ce2:lǐ # 峢 0x5ce3:yáo # 峣 0x5ce4:jiào,qiáo # 峤 0x5ce5:zhēng # 峥 0x5ce6:luán # 峦 0x5ce7:jiāo # 峧 0x5ce8:é # 峨 0x5ce9:é # 峩 0x5cea:yù # 峪 0x5ceb:xié,yé # 峫 0x5cec:bū # 峬 0x5ced:qiào # 峭 0x5cee:qún # 峮 0x5cef:fēng # 峯 0x5cf0:fēng # 峰 0x5cf1:náo # 峱 0x5cf2:lǐ # 峲 0x5cf3:yōu # 峳 0x5cf4:xiàn # 峴 0x5cf5:róng # 峵 0x5cf6:dǎo # 島 0x5cf7:shēn # 峷 0x5cf8:chéng # 峸 0x5cf9:tú # 峹 0x5cfa:gěng # 峺 0x5cfb:jùn # 峻 0x5cfc:gào # 峼 0x5cfd:xiá # 峽 0x5cfe:yín # 峾 0x5cff:wú # 峿 0x5d00:lǎng # 崀 0x5d01:kàn # 崁 0x5d02:láo # 崂 0x5d03:lái # 崃 0x5d04:xiǎn # 崄 0x5d05:què # 崅 0x5d06:kōng # 崆 0x5d07:chóng # 崇 0x5d08:chóng # 崈 0x5d09:tà # 崉 0x5d0b:huà # 崋 0x5d0c:jū # 崌 0x5d0d:lái # 崍 0x5d0e:qí # 崎 0x5d0f:mín # 崏 0x5d10:kūn # 崐 0x5d11:kūn # 崑 0x5d12:zú,cuì # 崒 0x5d13:gù # 崓 0x5d14:cuī # 崔 0x5d15:yá # 崕 0x5d16:yá # 崖 0x5d17:gǎng,gāng # 崗 0x5d18:lún # 崘 0x5d19:lún # 崙 0x5d1a:líng,léng # 崚 0x5d1b:jué # 崛 0x5d1c:duǒ # 崜 0x5d1d:zhēng # 崝 0x5d1e:guō # 崞 0x5d1f:yín # 崟 0x5d20:dōng,dòng # 崠 0x5d21:hán # 崡 0x5d22:zhēng # 崢 0x5d23:wěi # 崣 0x5d24:xiáo # 崤 0x5d25:pí,bǐ # 崥 0x5d26:yān # 崦 0x5d27:sōng # 崧 0x5d28:jié # 崨 0x5d29:bēng # 崩 0x5d2a:zú # 崪 0x5d2b:jué # 崫 0x5d2c:dōng # 崬 0x5d2d:zhǎn,chán # 崭 0x5d2e:gù # 崮 0x5d2f:yín # 崯 0x5d31:zè # 崱 0x5d32:huáng # 崲 0x5d33:yú # 崳 0x5d34:wǎi,wēi # 崴 0x5d35:yáng,dàng # 崵 0x5d36:fēng # 崶 0x5d37:qiú # 崷 0x5d38:yáng # 崸 0x5d39:tí # 崹 0x5d3a:yǐ # 崺 0x5d3b:zhì,shì # 崻 0x5d3c:shì,dié # 崼 0x5d3d:zǎi # 崽 0x5d3e:yǎo # 崾 0x5d3f:è # 崿 0x5d40:zhù # 嵀 0x5d41:kān,zhàn # 嵁 0x5d42:lǜ # 嵂 0x5d43:yǎn # 嵃 0x5d44:měi # 嵄 0x5d45:hán # 嵅 0x5d46:jī # 嵆 0x5d47:jī # 嵇 0x5d48:huàn # 嵈 0x5d49:tíng # 嵉 0x5d4a:shèng # 嵊 0x5d4b:méi # 嵋 0x5d4c:qiàn,kàn # 嵌 0x5d4d:wù,máo # 嵍 0x5d4e:yú # 嵎 0x5d4f:zōng # 嵏 0x5d50:lán # 嵐 0x5d51:kě,jié # 嵑 0x5d52:yán # 嵒 0x5d53:yán # 嵓 0x5d54:wēi,wěi # 嵔 0x5d55:zōng # 嵕 0x5d56:chá # 嵖 0x5d57:suì # 嵗 0x5d58:róng # 嵘 0x5d5a:qīn # 嵚 0x5d5b:yú # 嵛 0x5d5d:lǒu # 嵝 0x5d5e:tú # 嵞 0x5d5f:cuī # 嵟 0x5d60:xī # 嵠 0x5d61:wěng # 嵡 0x5d62:cāng # 嵢 0x5d63:dàng,táng # 嵣 0x5d64:róng,yíng # 嵤 0x5d65:jié # 嵥 0x5d66:kǎi,ái # 嵦 0x5d67:liú # 嵧 0x5d68:wù # 嵨 0x5d69:sōng # 嵩 0x5d6a:kāo,qiāo # 嵪 0x5d6b:zī # 嵫 0x5d6c:wéi # 嵬 0x5d6d:bēng # 嵭 0x5d6e:diān # 嵮 0x5d6f:cuó # 嵯 0x5d70:qīn,qiǎn # 嵰 0x5d71:yǒng # 嵱 0x5d72:niè # 嵲 0x5d73:cuó # 嵳 0x5d74:jǐ # 嵴 0x5d77:sǒng # 嵷 0x5d78:zǒng # 嵸 0x5d79:jiàng # 嵹 0x5d7a:liáo # 嵺 0x5d7c:chǎn # 嵼 0x5d7d:dié,dì # 嵽 0x5d7e:cēn # 嵾 0x5d7f:dǐng # 嵿 0x5d80:tū # 嶀 0x5d81:lǒu # 嶁 0x5d82:zhàng # 嶂 0x5d83:zhǎn,chán # 嶃 0x5d84:zhǎn,chán # 嶄 0x5d85:áo,ào # 嶅 0x5d86:cáo # 嶆 0x5d87:qū # 嶇 0x5d88:qiāng # 嶈 0x5d89:wěi # 嶉 0x5d8a:zuǐ # 嶊 0x5d8b:dǎo # 嶋 0x5d8c:dǎo # 嶌 0x5d8d:xí # 嶍 0x5d8e:yù # 嶎 0x5d8f:pǐ,pèi # 嶏 0x5d90:lóng # 嶐 0x5d91:xiàng # 嶑 0x5d92:céng # 嶒 0x5d93:bō # 嶓 0x5d94:qīn # 嶔 0x5d95:jiāo # 嶕 0x5d96:yān # 嶖 0x5d97:láo # 嶗 0x5d98:zhàn # 嶘 0x5d99:lín # 嶙 0x5d9a:liáo # 嶚 0x5d9b:liáo # 嶛 0x5d9c:qín # 嶜 0x5d9d:dèng # 嶝 0x5d9e:tuò # 嶞 0x5d9f:zūn # 嶟 0x5da0:jiào,qiáo # 嶠 0x5da1:jué,guì # 嶡 0x5da2:yáo # 嶢 0x5da3:jiāo # 嶣 0x5da4:yáo # 嶤 0x5da5:jué # 嶥 0x5da6:zhān,shàn # 嶦 0x5da7:yì # 嶧 0x5da8:xué # 嶨 0x5da9:náo # 嶩 0x5daa:yè # 嶪 0x5dab:yè # 嶫 0x5dac:yí # 嶬 0x5dad:niè # 嶭 0x5dae:xiǎn # 嶮 0x5daf:jí # 嶯 0x5db0:xiè,jiè # 嶰 0x5db1:kě,jié # 嶱 0x5db2:guī,xī,juàn # 嶲 0x5db3:dì # 嶳 0x5db4:ào # 嶴 0x5db5:zuì # 嶵 0x5db7:yí # 嶷 0x5db8:róng # 嶸 0x5db9:dǎo # 嶹 0x5dba:lǐng # 嶺 0x5dbb:jié # 嶻 0x5dbc:yǔ # 嶼 0x5dbd:yuè # 嶽 0x5dbe:yǐn # 嶾 0x5dc0:jié # 巀 0x5dc1:lì,liè # 巁 0x5dc2:guī,xī,juàn # 巂 0x5dc3:lóng # 巃 0x5dc4:lóng # 巄 0x5dc5:diān # 巅 0x5dc6:yíng,hōng # 巆 0x5dc7:xī # 巇 0x5dc8:jú # 巈 0x5dc9:chán # 巉 0x5dca:yǐng # 巊 0x5dcb:kuī # 巋 0x5dcc:yán # 巌 0x5dcd:wēi # 巍 0x5dce:náo # 巎 0x5dcf:quán # 巏 0x5dd0:chǎo # 巐 0x5dd1:cuán # 巑 0x5dd2:luán # 巒 0x5dd3:diān # 巓 0x5dd4:diān # 巔 0x5dd6:yán # 巖 0x5dd7:yán # 巗 0x5dd8:yǎn # 巘 0x5dd9:kuí # 巙 0x5dda:yǎn # 巚 0x5ddb:chuān # 巛 0x5ddc:kuài # 巜 0x5ddd:chuān # 川 0x5dde:zhōu # 州 0x5ddf:huāng # 巟 0x5de0:jīng,xíng # 巠 0x5de1:xún # 巡 0x5de2:cháo # 巢 0x5de3:cháo # 巣 0x5de4:liè # 巤 0x5de5:gōng # 工 0x5de6:zuǒ # 左 0x5de7:qiǎo # 巧 0x5de8:jù # 巨 0x5de9:gǒng # 巩 0x5deb:wū # 巫 0x5dee:chà,chā,chāi,cī # 差 0x5def:qiú # 巯 0x5df0:qiú # 巰 0x5df1:jǐ # 己 0x5df2:yǐ # 已 0x5df3:sì # 巳 0x5df4:bā # 巴 0x5df5:zhī # 巵 0x5df6:zhāo # 巶 0x5df7:xiàng,hàng # 巷 0x5df8:yí # 巸 0x5df9:jǐn # 巹 0x5dfa:xùn # 巺 0x5dfb:juàn,juǎn # 巻 0x5dfd:xùn # 巽 0x5dfe:jīn # 巾 0x5dff:fú # 巿 0x5e00:zā # 帀 0x5e01:bì # 币 0x5e02:shì # 市 0x5e03:bù # 布 0x5e04:dīng # 帄 0x5e05:shuài # 帅 0x5e06:fān # 帆 0x5e07:niè # 帇 0x5e08:shī # 师 0x5e09:fēn # 帉 0x5e0a:pà # 帊 0x5e0b:zhǐ # 帋 0x5e0c:xī # 希 0x5e0d:hù # 帍 0x5e0e:dàn # 帎 0x5e0f:wéi # 帏 0x5e10:zhàng # 帐 0x5e11:tǎng,nú # 帑 0x5e12:dài # 帒 0x5e13:mò,wà # 帓 0x5e14:pèi # 帔 0x5e15:pà # 帕 0x5e16:tiè,tiě,tiē # 帖 0x5e17:fú # 帗 0x5e18:lián # 帘 0x5e19:zhì # 帙 0x5e1a:zhǒu # 帚 0x5e1b:bó # 帛 0x5e1c:zhì # 帜 0x5e1d:dì # 帝 0x5e1e:mò # 帞 0x5e1f:yì # 帟 0x5e20:yì # 帠 0x5e21:píng # 帡 0x5e22:qià # 帢 0x5e23:juàn,juǎn # 帣 0x5e24:rú # 帤 0x5e25:shuài # 帥 0x5e26:dài # 带 0x5e27:zhēn # 帧 0x5e28:shuì # 帨 0x5e29:qiāo # 帩 0x5e2a:zhēn # 帪 0x5e2b:shī # 師 0x5e2c:qún # 帬 0x5e2d:xí # 席 0x5e2e:bāng # 帮 0x5e2f:dài # 帯 0x5e30:guī # 帰 0x5e31:chóu,dào # 帱 0x5e32:píng # 帲 0x5e33:zhàng # 帳 0x5e34:jiǎn,jiān,sàn # 帴 0x5e35:wān # 帵 0x5e36:dài # 帶 0x5e37:wéi # 帷 0x5e38:cháng # 常 0x5e39:shà,qiè # 帹 0x5e3a:qí,jì # 帺 0x5e3b:zé # 帻 0x5e3c:guó # 帼 0x5e3d:mào # 帽 0x5e3e:zhǔ # 帾 0x5e3f:hóu # 帿 0x5e40:zhēn # 幀 0x5e41:zhèng # 幁 0x5e42:mì # 幂 0x5e43:wéi # 幃 0x5e44:wò # 幄 0x5e45:fú # 幅 0x5e46:yì # 幆 0x5e47:bāng # 幇 0x5e48:píng # 幈 0x5e4a:gōng # 幊 0x5e4b:pán # 幋 0x5e4c:huǎng # 幌 0x5e4d:tāo # 幍 0x5e4e:mì # 幎 0x5e4f:jià # 幏 0x5e50:téng # 幐 0x5e51:huī # 幑 0x5e52:zhōng # 幒 0x5e53:shān,qiāo,shēn # 幓 0x5e54:màn # 幔 0x5e55:mù # 幕 0x5e56:biāo # 幖 0x5e57:guó # 幗 0x5e58:zé # 幘 0x5e59:mù # 幙 0x5e5a:bāng # 幚 0x5e5b:zhàng # 幛 0x5e5c:jǐng # 幜 0x5e5d:chǎn,chàn # 幝 0x5e5e:fú # 幞 0x5e5f:zhì # 幟 0x5e60:hū # 幠 0x5e61:fān # 幡 0x5e62:chuáng,zhuàng # 幢 0x5e63:bì # 幣 0x5e66:mì # 幦 0x5e67:qiāo # 幧 0x5e68:chān,chàn # 幨 0x5e69:fén # 幩 0x5e6a:méng # 幪 0x5e6b:bāng # 幫 0x5e6c:chóu,dào # 幬 0x5e6d:miè # 幭 0x5e6e:chú # 幮 0x5e6f:jié # 幯 0x5e70:xiǎn # 幰 0x5e71:lán # 幱 0x5e72:gān,gàn # 干 0x5e73:píng # 平 0x5e74:nián # 年 0x5e75:jiān # 幵 0x5e76:bìng,bīng # 并 0x5e77:bìng,bīng # 幷 0x5e78:xìng # 幸 0x5e79:gàn # 幹 0x5e7a:yāo # 幺 0x5e7b:huàn # 幻 0x5e7c:yòu # 幼 0x5e7d:yōu # 幽 0x5e7e:jī,jǐ # 幾 0x5e7f:guǎng,ān # 广 0x5e80:pǐ # 庀 0x5e81:tīng # 庁 0x5e82:zè # 庂 0x5e83:guǎng # 広 0x5e84:zhuāng # 庄 0x5e85:mó,mā,me # 庅 0x5e86:qìng # 庆 0x5e87:bì # 庇 0x5e88:qín # 庈 0x5e89:dùn,tún # 庉 0x5e8a:chuáng # 床 0x5e8b:guǐ # 庋 0x5e8c:yǎ # 庌 0x5e8d:bài,tīng # 庍 0x5e8e:jiè # 庎 0x5e8f:xù # 序 0x5e90:lú # 庐 0x5e91:wǔ # 庑 0x5e93:kù # 库 0x5e94:yīng,yìng # 应 0x5e95:dǐ,de # 底 0x5e96:páo # 庖 0x5e97:diàn # 店 0x5e98:yā # 庘 0x5e99:miào # 庙 0x5e9a:gēng # 庚 0x5e9b:cì # 庛 0x5e9c:fǔ # 府 0x5e9d:tóng # 庝 0x5e9e:páng # 庞 0x5e9f:fèi # 废 0x5ea0:xiáng # 庠 0x5ea1:yǐ # 庡 0x5ea2:zhì # 庢 0x5ea3:tiāo # 庣 0x5ea4:zhì # 庤 0x5ea5:xiū # 庥 0x5ea6:dù,duó # 度 0x5ea7:zuò # 座 0x5ea8:xiāo # 庨 0x5ea9:tú # 庩 0x5eaa:guǐ # 庪 0x5eab:kù # 庫 0x5eac:máng,méng,páng # 庬 0x5ead:tíng # 庭 0x5eae:yóu # 庮 0x5eaf:bū # 庯 0x5eb0:bìng,píng # 庰 0x5eb1:chěng # 庱 0x5eb2:lái # 庲 0x5eb3:bēi,bì,pí # 庳 0x5eb4:jī,cuò # 庴 0x5eb5:ān # 庵 0x5eb6:shù # 庶 0x5eb7:kāng # 康 0x5eb8:yōng # 庸 0x5eb9:tuǒ # 庹 0x5eba:sōng # 庺 0x5ebb:shù # 庻 0x5ebc:qǐng # 庼 0x5ebd:yù # 庽 0x5ebe:yǔ # 庾 0x5ebf:miào # 庿 0x5ec0:sōu # 廀 0x5ec1:cè # 廁 0x5ec2:xiāng # 廂 0x5ec3:fèi # 廃 0x5ec4:jiù # 廄 0x5ec5:è # 廅 0x5ec6:guī,wěi,huì # 廆 0x5ec7:liù # 廇 0x5ec8:shà,xià # 廈 0x5ec9:lián # 廉 0x5eca:láng # 廊 0x5ecb:sōu # 廋 0x5ecc:zhì # 廌 0x5ecd:bù # 廍 0x5ece:qǐng # 廎 0x5ecf:jiù # 廏 0x5ed0:jiù # 廐 0x5ed1:jǐn,qín # 廑 0x5ed2:áo # 廒 0x5ed3:kuò # 廓 0x5ed4:lóu # 廔 0x5ed5:yìn # 廕 0x5ed6:liào # 廖 0x5ed7:dài # 廗 0x5ed8:lù # 廘 0x5ed9:yì # 廙 0x5eda:chú # 廚 0x5edb:chán # 廛 0x5edc:tú # 廜 0x5edd:sī # 廝 0x5ede:xīn # 廞 0x5edf:miào # 廟 0x5ee0:chǎng # 廠 0x5ee1:wǔ # 廡 0x5ee2:fèi # 廢 0x5ee3:guǎng # 廣 0x5ee5:kuài # 廥 0x5ee6:bì # 廦 0x5ee7:qiáng,sè # 廧 0x5ee8:xiè # 廨 0x5ee9:lǐn # 廩 0x5eea:lǐn # 廪 0x5eeb:liáo # 廫 0x5eec:lú # 廬 0x5eee:yǐng # 廮 0x5eef:xiān # 廯 0x5ef0:tīng # 廰 0x5ef1:yōng # 廱 0x5ef2:lí # 廲 0x5ef3:tīng # 廳 0x5ef4:yǐn,yìn # 廴 0x5ef5:xún # 廵 0x5ef6:yán # 延 0x5ef7:tíng # 廷 0x5ef8:dí # 廸 0x5ef9:pò,pǎi # 廹 0x5efa:jiàn # 建 0x5efb:huí # 廻 0x5efc:nǎi # 廼 0x5efd:huí # 廽 0x5efe:gǒng # 廾 0x5eff:niàn # 廿 0x5f00:kāi # 开 0x5f01:biàn # 弁 0x5f02:yì # 异 0x5f03:qì # 弃 0x5f04:nòng,lòng # 弄 0x5f05:fèn # 弅 0x5f06:jǔ # 弆 0x5f07:yǎn # 弇 0x5f08:yì # 弈 0x5f09:zàng # 弉 0x5f0a:bì # 弊 0x5f0b:yì # 弋 0x5f0c:yī # 弌 0x5f0d:èr # 弍 0x5f0e:sān # 弎 0x5f0f:shì # 式 0x5f10:èr # 弐 0x5f11:shì # 弑 0x5f12:shì # 弒 0x5f13:gōng # 弓 0x5f14:diào # 弔 0x5f15:yǐn # 引 0x5f16:hù # 弖 0x5f17:fú # 弗 0x5f18:hóng # 弘 0x5f19:wū # 弙 0x5f1a:tuí # 弚 0x5f1b:chí # 弛 0x5f1c:jiàng # 弜 0x5f1d:bà # 弝 0x5f1e:shěn # 弞 0x5f1f:dì,tì,tuí # 弟 0x5f20:zhāng # 张 0x5f21:jué,zhāng # 弡 0x5f22:tāo # 弢 0x5f23:fǔ # 弣 0x5f24:dǐ # 弤 0x5f25:mí,mǐ # 弥 0x5f26:xián # 弦 0x5f27:hú # 弧 0x5f28:chāo # 弨 0x5f29:nǔ # 弩 0x5f2a:jìng # 弪 0x5f2b:zhěn # 弫 0x5f2c:yi # 弬 0x5f2d:mǐ # 弭 0x5f2e:juàn,quān # 弮 0x5f2f:wān # 弯 0x5f30:shāo # 弰 0x5f31:ruò # 弱 0x5f32:xuān,yuān # 弲 0x5f33:jìng # 弳 0x5f34:diāo # 弴 0x5f35:zhāng # 張 0x5f36:jiàng # 弶 0x5f37:qiáng,qiǎng,jiàng # 強 0x5f38:péng # 弸 0x5f39:dàn,tán # 弹 0x5f3a:qiáng,qiǎng,jiàng # 强 0x5f3b:bì # 弻 0x5f3c:bì # 弼 0x5f3d:shè # 弽 0x5f3e:dàn,tán # 弾 0x5f3f:jiǎn # 弿 0x5f40:gòu # 彀 0x5f42:fā # 彂 0x5f43:bì # 彃 0x5f44:kōu # 彄 0x5f46:biè # 彆 0x5f47:xiāo # 彇 0x5f48:dàn,tán # 彈 0x5f49:guō # 彉 0x5f4a:qiáng,qiǎng,jiàng # 彊 0x5f4b:hóng # 彋 0x5f4c:mí,mǐ # 彌 0x5f4d:guō # 彍 0x5f4e:wān # 彎 0x5f4f:jué # 彏 0x5f50:jì,xuě # 彐 0x5f51:jì # 彑 0x5f52:guī # 归 0x5f53:dāng,dàng # 当 0x5f54:lù # 彔 0x5f55:lù # 录 0x5f56:tuàn # 彖 0x5f57:huì # 彗 0x5f58:zhì # 彘 0x5f59:huì # 彙 0x5f5a:huì # 彚 0x5f5b:yí # 彛 0x5f5c:yí # 彜 0x5f5d:yí # 彝 0x5f5e:yí # 彞 0x5f5f:huò # 彟 0x5f60:huò # 彠 0x5f61:shān,xiǎn # 彡 0x5f62:xíng # 形 0x5f63:wén # 彣 0x5f64:tóng # 彤 0x5f65:yàn # 彥 0x5f66:yàn # 彦 0x5f67:yù # 彧 0x5f68:chī # 彨 0x5f69:cǎi # 彩 0x5f6a:biāo # 彪 0x5f6b:diāo # 彫 0x5f6c:bīn # 彬 0x5f6d:péng,bāng # 彭 0x5f6e:yǒng # 彮 0x5f6f:piāo,piào # 彯 0x5f70:zhāng # 彰 0x5f71:yǐng # 影 0x5f72:chī # 彲 0x5f73:chì # 彳 0x5f74:zhuó,bó # 彴 0x5f75:tuǒ,yí # 彵 0x5f76:jí # 彶 0x5f77:páng,fǎng # 彷 0x5f78:zhōng # 彸 0x5f79:yì # 役 0x5f7a:wǎng # 彺 0x5f7b:chè # 彻 0x5f7c:bǐ # 彼 0x5f7d:dī # 彽 0x5f7e:líng # 彾 0x5f7f:fù # 彿 0x5f80:wǎng # 往 0x5f81:zhēng # 征 0x5f82:cú # 徂 0x5f83:wǎng # 徃 0x5f84:jìng # 径 0x5f85:dài,dāi # 待 0x5f86:xī # 徆 0x5f87:xùn # 徇 0x5f88:hěn # 很 0x5f89:yáng # 徉 0x5f8a:huái # 徊 0x5f8b:lǜ # 律 0x5f8c:hòu # 後 0x5f8d:wàng,jiā,wā # 徍 0x5f8e:chěng,zhèng # 徎 0x5f8f:zhì # 徏 0x5f90:xú # 徐 0x5f91:jìng # 徑 0x5f92:tú # 徒 0x5f93:cóng # 従 0x5f95:lài,lái # 徕 0x5f96:cóng # 徖 0x5f97:dé,děi,de # 得 0x5f98:pái # 徘 0x5f99:xǐ # 徙 0x5f9b:jì # 徛 0x5f9c:cháng # 徜 0x5f9d:zhì # 徝 0x5f9e:cóng,zòng # 從 0x5f9f:zhōu # 徟 0x5fa0:lái,lài # 徠 0x5fa1:yù # 御 0x5fa2:xiè # 徢 0x5fa3:jiè # 徣 0x5fa4:jiàn # 徤 0x5fa5:shì,tǐ # 徥 0x5fa6:jiǎ,xiá # 徦 0x5fa7:biàn # 徧 0x5fa8:huáng # 徨 0x5fa9:fù # 復 0x5faa:xún # 循 0x5fab:wěi # 徫 0x5fac:páng # 徬 0x5fad:yáo # 徭 0x5fae:wēi # 微 0x5faf:xī # 徯 0x5fb0:zhēng # 徰 0x5fb1:piào # 徱 0x5fb2:tí,chí # 徲 0x5fb3:dé # 徳 0x5fb4:zhǐ,zhēng # 徴 0x5fb5:zhǐ,zhēng # 徵 0x5fb6:bié # 徶 0x5fb7:dé # 德 0x5fb8:zhǒng,chōng # 徸 0x5fb9:chè # 徹 0x5fba:jiǎo,yáo # 徺 0x5fbb:huì # 徻 0x5fbc:jiǎo,jiào # 徼 0x5fbd:huī # 徽 0x5fbe:méi # 徾 0x5fbf:lòng,lǒng # 徿 0x5fc0:xiāng # 忀 0x5fc1:bào # 忁 0x5fc2:qú,jù # 忂 0x5fc3:xīn # 心 0x5fc5:bì # 必 0x5fc6:yì # 忆 0x5fc7:lè # 忇 0x5fc8:rén # 忈 0x5fc9:dāo # 忉 0x5fca:dìng,tìng # 忊 0x5fcb:gǎi # 忋 0x5fcc:jì # 忌 0x5fcd:rěn # 忍 0x5fce:rén # 忎 0x5fcf:chàn # 忏 0x5fd0:tǎn # 忐 0x5fd1:tè # 忑 0x5fd2:tè,tuī,tēi # 忒 0x5fd3:gān,hàn # 忓 0x5fd4:yì,qì # 忔 0x5fd5:shì,tài # 忕 0x5fd6:cǔn # 忖 0x5fd7:zhì # 志 0x5fd8:wàng # 忘 0x5fd9:máng # 忙 0x5fda:xī,liě # 忚 0x5fdb:fān # 忛 0x5fdc:yīng,yìng # 応 0x5fdd:tiǎn # 忝 0x5fde:mǐn,wěn,mín # 忞 0x5fdf:mǐn,wěn,mín # 忟 0x5fe0:zhōng # 忠 0x5fe1:chōng # 忡 0x5fe2:wù # 忢 0x5fe3:jí # 忣 0x5fe4:wǔ # 忤 0x5fe5:xì # 忥 0x5fe6:jiá # 忦 0x5fe7:yōu # 忧 0x5fe8:wán # 忨 0x5fe9:cōng # 忩 0x5fea:sōng,zhōng # 忪 0x5feb:kuài # 快 0x5fec:yù,shū # 忬 0x5fed:biàn # 忭 0x5fee:zhì # 忮 0x5fef:qí,shì # 忯 0x5ff0:cuì # 忰 0x5ff1:chén # 忱 0x5ff2:tài # 忲 0x5ff3:tún,zhūn,dùn # 忳 0x5ff4:qián,qín # 忴 0x5ff5:niàn # 念 0x5ff6:hún # 忶 0x5ff7:xiōng # 忷 0x5ff8:niǔ # 忸 0x5ff9:kuáng,wǎng # 忹 0x5ffa:xiān # 忺 0x5ffb:xīn # 忻 0x5ffc:kāng,hàng # 忼 0x5ffd:hū # 忽 0x5ffe:kài,xì # 忾 0x5fff:fèn # 忿 0x6000:huái # 怀 0x6001:tài # 态 0x6002:sǒng # 怂 0x6003:wǔ # 怃 0x6004:òu # 怄 0x6005:chàng # 怅 0x6006:chuàng # 怆 0x6007:jù # 怇 0x6008:yì # 怈 0x6009:bǎo,bào # 怉 0x600a:chāo # 怊 0x600b:mín,mén # 怋 0x600c:pēi # 怌 0x600d:zuò,zhà # 怍 0x600e:zěn # 怎 0x600f:yàng # 怏 0x6010:kòu,jù # 怐 0x6011:bàn # 怑 0x6012:nù # 怒 0x6013:náo,niú # 怓 0x6014:zhēng # 怔 0x6015:pà # 怕 0x6016:bù # 怖 0x6017:tiē,zhān # 怗 0x6018:hù,gù # 怘 0x6019:hù # 怙 0x601a:cū,jù,zū # 怚 0x601b:dá # 怛 0x601c:lián # 怜 0x601d:sī,sāi # 思 0x601e:yóu,chóu # 怞 0x601f:dì # 怟 0x6020:dài # 怠 0x6021:yí # 怡 0x6022:tū,dié # 怢 0x6023:yóu # 怣 0x6024:fū # 怤 0x6025:jí # 急 0x6026:pēng # 怦 0x6027:xìng # 性 0x6028:yuàn # 怨 0x6029:ní # 怩 0x602a:guài # 怪 0x602b:fú # 怫 0x602c:xì # 怬 0x602d:bì # 怭 0x602e:yōu,yào # 怮 0x602f:qiè # 怯 0x6030:xuàn # 怰 0x6031:cōng # 怱 0x6032:bǐng # 怲 0x6033:huǎng # 怳 0x6034:xù,xuè # 怴 0x6035:chù # 怵 0x6036:bì,pī # 怶 0x6037:shù # 怷 0x6038:xī,shù # 怸 0x6039:tān # 怹 0x603b:zǒng # 总 0x603c:duì # 怼 0x603f:yì # 怿 0x6040:shì # 恀 0x6041:nèn,nín # 恁 0x6042:xún # 恂 0x6043:shì # 恃 0x6044:xì # 恄 0x6045:lǎo # 恅 0x6046:héng # 恆 0x6047:kuāng # 恇 0x6048:móu # 恈 0x6049:zhǐ # 恉 0x604a:xié # 恊 0x604b:liàn # 恋 0x604c:tiāo,yáo # 恌 0x604d:huǎng # 恍 0x604e:dié # 恎 0x604f:hào # 恏 0x6050:kǒng # 恐 0x6051:guǐ # 恑 0x6052:héng # 恒 0x6053:xī,qī,xù # 恓 0x6054:xiào,jiǎo # 恔 0x6055:shù # 恕 0x6057:hū,kuā # 恗 0x6058:qiū # 恘 0x6059:yàng # 恙 0x605a:huì # 恚 0x605b:huí # 恛 0x605c:chì # 恜 0x605d:jiá # 恝 0x605e:yí # 恞 0x605f:xiōng # 恟 0x6060:guài # 恠 0x6061:lìn # 恡 0x6062:huī # 恢 0x6063:zì # 恣 0x6064:xù # 恤 0x6065:chǐ # 恥 0x6066:shàng # 恦 0x6067:nǜ # 恧 0x6068:hèn # 恨 0x6069:ēn # 恩 0x606a:kè # 恪 0x606b:dòng # 恫 0x606c:tián # 恬 0x606d:gōng # 恭 0x606e:quán,zhuān # 恮 0x606f:xī # 息 0x6070:qià # 恰 0x6071:yuè # 恱 0x6072:pēng # 恲 0x6073:kěn # 恳 0x6074:dé # 恴 0x6075:huì # 恵 0x6076:è,wù,ě,wū # 恶 0x6078:tòng # 恸 0x6079:yān # 恹 0x607a:kǎi # 恺 0x607b:cè # 恻 0x607c:nǎo # 恼 0x607d:yùn # 恽 0x607e:máng # 恾 0x607f:yǒng # 恿 0x6080:yǒng # 悀 0x6081:yuān,juàn # 悁 0x6082:pī,pǐ # 悂 0x6083:kǔn # 悃 0x6084:qiǎo,qiāo # 悄 0x6085:yuè # 悅 0x6086:yù,shū # 悆 0x6087:tú # 悇 0x6088:jiè,kè # 悈 0x6089:xī # 悉 0x608a:zhé # 悊 0x608b:lìn # 悋 0x608c:tì # 悌 0x608d:hàn # 悍 0x608e:hào,jiào # 悎 0x608f:qiè # 悏 0x6090:tì # 悐 0x6091:bù # 悑 0x6092:yì # 悒 0x6093:qiàn # 悓 0x6094:huǐ # 悔 0x6095:xī # 悕 0x6096:bèi # 悖 0x6097:mán,mèn # 悗 0x6098:yī,yì # 悘 0x6099:hēng,hèng # 悙 0x609a:sǒng # 悚 0x609b:quān # 悛 0x609c:chěng # 悜 0x609d:kuī,lǐ # 悝 0x609e:wù # 悞 0x609f:wù # 悟 0x60a0:yōu # 悠 0x60a1:lí # 悡 0x60a2:liàng # 悢 0x60a3:huàn # 患 0x60a4:cōng # 悤 0x60a5:yì,niàn # 悥 0x60a6:yuè # 悦 0x60a7:lì # 悧 0x60a8:nín # 您 0x60a9:nǎo # 悩 0x60aa:è # 悪 0x60ab:què # 悫 0x60ac:xuán # 悬 0x60ad:qiān # 悭 0x60ae:wù # 悮 0x60af:mǐn # 悯 0x60b0:cóng # 悰 0x60b1:fěi # 悱 0x60b2:bēi # 悲 0x60b3:dé # 悳 0x60b4:cuì # 悴 0x60b5:chàng # 悵 0x60b6:mèn,mēn # 悶 0x60b7:lì # 悷 0x60b8:jì # 悸 0x60b9:guàn # 悹 0x60ba:guàn # 悺 0x60bb:xìng # 悻 0x60bc:dào # 悼 0x60bd:qī # 悽 0x60be:kōng,kǒng # 悾 0x60bf:tiǎn # 悿 0x60c0:lǔn,lùn # 惀 0x60c1:xī # 惁 0x60c2:kǎn # 惂 0x60c3:gǔn # 惃 0x60c4:nì # 惄 0x60c5:qíng # 情 0x60c6:chóu # 惆 0x60c7:dūn # 惇 0x60c8:guǒ # 惈 0x60c9:zhān # 惉 0x60ca:jīng # 惊 0x60cb:wǎn # 惋 0x60cc:yuān,wǎn # 惌 0x60cd:jīn # 惍 0x60ce:jì # 惎 0x60cf:lán,lín # 惏 0x60d0:yù,xù # 惐 0x60d1:huò # 惑 0x60d2:hé,hè # 惒 0x60d3:juàn,quán # 惓 0x60d4:tán,dàn # 惔 0x60d5:tì # 惕 0x60d6:tì # 惖 0x60d7:niàn # 惗 0x60d8:wǎng # 惘 0x60d9:chuò,chuì # 惙 0x60da:hū # 惚 0x60db:hūn,mèn # 惛 0x60dc:xī # 惜 0x60dd:chǎng,tǎng # 惝 0x60de:xīn # 惞 0x60df:wéi # 惟 0x60e0:huì # 惠 0x60e1:è,wù,ě,wū # 惡 0x60e2:suǒ,ruǐ # 惢 0x60e3:zǒng # 惣 0x60e4:jiān # 惤 0x60e5:yǒng # 惥 0x60e6:diàn # 惦 0x60e7:jù # 惧 0x60e8:cǎn # 惨 0x60e9:chéng # 惩 0x60ea:dé # 惪 0x60eb:bèi # 惫 0x60ec:qiè # 惬 0x60ed:cán # 惭 0x60ee:dàn,dá # 惮 0x60ef:guàn # 惯 0x60f0:duò # 惰 0x60f1:nǎo # 惱 0x60f2:yùn # 惲 0x60f3:xiǎng # 想 0x60f4:zhuì # 惴 0x60f5:dié # 惵 0x60f6:huáng # 惶 0x60f7:chǔn # 惷 0x60f8:qióng # 惸 0x60f9:rě # 惹 0x60fa:xīng # 惺 0x60fb:cè # 惻 0x60fc:biǎn # 惼 0x60fd:mǐn # 惽 0x60fe:zōng # 惾 0x60ff:tí,shì # 惿 0x6100:qiǎo # 愀 0x6101:chóu # 愁 0x6102:bèi # 愂 0x6103:xuān # 愃 0x6104:wēi # 愄 0x6105:gé # 愅 0x6106:qiān # 愆 0x6107:wěi # 愇 0x6108:yù # 愈 0x6109:yú,tōu # 愉 0x610a:bì # 愊 0x610b:xuān # 愋 0x610c:huàn # 愌 0x610d:mǐn # 愍 0x610e:bì # 愎 0x610f:yì # 意 0x6110:miǎn # 愐 0x6111:yǒng # 愑 0x6112:qì,kài # 愒 0x6113:dàng,shāng,táng,yáng # 愓 0x6114:yīn # 愔 0x6115:è # 愕 0x6116:chén,xìn,dān # 愖 0x6117:mào # 愗 0x6118:kè,qià # 愘 0x6119:kè # 愙 0x611a:yú # 愚 0x611b:ài # 愛 0x611c:qiè # 愜 0x611d:yǎn # 愝 0x611e:nuò # 愞 0x611f:gǎn # 感 0x6120:yùn # 愠 0x6121:còng,sōng # 愡 0x6122:sāi,sī,sǐ # 愢 0x6123:lèng # 愣 0x6124:fèn # 愤 0x6126:kuì # 愦 0x6127:kuì # 愧 0x6128:què # 愨 0x6129:gōng,gòng,hǒng # 愩 0x612a:yún # 愪 0x612b:sù # 愫 0x612c:sù,shuò # 愬 0x612d:qí # 愭 0x612e:yáo,yào # 愮 0x612f:sǒng # 愯 0x6130:huàng # 愰 0x6131:jí # 愱 0x6132:gǔ # 愲 0x6133:jù # 愳 0x6134:chuàng # 愴 0x6135:nì # 愵 0x6136:xié # 愶 0x6137:kǎi # 愷 0x6138:zhěng # 愸 0x6139:yǒng # 愹 0x613a:cǎo # 愺 0x613b:xùn # 愻 0x613c:shèn # 愼 0x613d:bó # 愽 0x613e:kài,xì # 愾 0x613f:yuàn # 愿 0x6140:xì,xié # 慀 0x6141:hùn # 慁 0x6142:yǒng # 慂 0x6143:yǎng # 慃 0x6144:lì # 慄 0x6145:cǎo,sāo # 慅 0x6146:tāo # 慆 0x6147:yīn # 慇 0x6148:cí # 慈 0x6149:xù,chù # 慉 0x614a:qiàn,qiè # 慊 0x614b:tài # 態 0x614c:huāng # 慌 0x614d:yùn # 慍 0x614e:shèn # 慎 0x614f:mǐng # 慏 0x6151:shè # 慑 0x6152:cáo,cóng # 慒 0x6153:piāo # 慓 0x6154:mù # 慔 0x6155:mù # 慕 0x6156:guó # 慖 0x6157:chì # 慗 0x6158:cǎn # 慘 0x6159:cán # 慙 0x615a:cán # 慚 0x615b:cuī # 慛 0x615c:mín # 慜 0x615d:tè # 慝 0x615e:zhāng # 慞 0x615f:tòng # 慟 0x6160:ào,áo # 慠 0x6161:shuǎng # 慡 0x6162:màn # 慢 0x6163:guàn # 慣 0x6164:què # 慤 0x6165:zào # 慥 0x6166:jiù # 慦 0x6167:huì # 慧 0x6168:kǎi # 慨 0x6169:lián,liǎn # 慩 0x616a:òu # 慪 0x616b:sǒng # 慫 0x616c:qín,jìn,jǐn # 慬 0x616d:yìn # 慭 0x616e:lǜ # 慮 0x616f:shāng # 慯 0x6170:wèi # 慰 0x6171:tuán # 慱 0x6172:mán # 慲 0x6173:qiān # 慳 0x6174:shè # 慴 0x6175:yōng # 慵 0x6176:qìng # 慶 0x6177:kāng # 慷 0x6178:dì,chì # 慸 0x6179:zhí,zhé # 慹 0x617a:lóu,lǚ # 慺 0x617b:juàn # 慻 0x617c:qī # 慼 0x617d:qī # 慽 0x617e:yù # 慾 0x617f:píng # 慿 0x6180:liáo # 憀 0x6181:còng # 憁 0x6182:yōu # 憂 0x6183:chōng # 憃 0x6184:zhī,zhì # 憄 0x6185:tòng # 憅 0x6186:chēng # 憆 0x6187:qì # 憇 0x6188:qū # 憈 0x6189:péng # 憉 0x618a:bèi # 憊 0x618b:biē # 憋 0x618c:qióng # 憌 0x618d:jiāo # 憍 0x618e:zēng # 憎 0x618f:chì # 憏 0x6190:lián # 憐 0x6191:píng # 憑 0x6192:kuì # 憒 0x6193:huì # 憓 0x6194:qiáo # 憔 0x6195:chéng,dèng,zhèng # 憕 0x6196:yìn # 憖 0x6197:yìn # 憗 0x6198:xǐ,xī # 憘 0x6199:xǐ # 憙 0x619a:dàn,dá # 憚 0x619b:tán # 憛 0x619c:duò # 憜 0x619d:duì # 憝 0x619e:duì,dùn,tūn # 憞 0x619f:sù # 憟 0x61a0:jué # 憠 0x61a1:cè # 憡 0x61a2:xiāo,jiāo # 憢 0x61a3:fān # 憣 0x61a4:fèn # 憤 0x61a5:láo # 憥 0x61a6:lào,láo # 憦 0x61a7:chōng # 憧 0x61a8:hān # 憨 0x61a9:qì # 憩 0x61aa:xián,xiàn # 憪 0x61ab:mǐn # 憫 0x61ac:jǐng # 憬 0x61ad:liǎo,liáo # 憭 0x61ae:wǔ # 憮 0x61af:cǎn # 憯 0x61b0:jué # 憰 0x61b1:cù # 憱 0x61b2:xiàn # 憲 0x61b3:tǎn # 憳 0x61b4:shéng # 憴 0x61b5:pī # 憵 0x61b6:yì # 憶 0x61b7:chù # 憷 0x61b8:xiān # 憸 0x61b9:náo,nǎo,náng # 憹 0x61ba:dàn # 憺 0x61bb:tǎn # 憻 0x61bc:jǐng,jìng # 憼 0x61bd:sōng # 憽 0x61be:hàn # 憾 0x61bf:jiǎo,jǐ # 憿 0x61c0:wèi # 懀 0x61c1:xuān,huān # 懁 0x61c2:dǒng # 懂 0x61c3:qín # 懃 0x61c4:qín # 懄 0x61c5:jù # 懅 0x61c6:cǎo,sāo,sào # 懆 0x61c7:kěn # 懇 0x61c8:xiè # 懈 0x61c9:yīng,yìng # 應 0x61ca:ào # 懊 0x61cb:mào # 懋 0x61cc:yì # 懌 0x61cd:lǐn # 懍 0x61ce:sè # 懎 0x61cf:jùn # 懏 0x61d0:huái # 懐 0x61d1:mèn # 懑 0x61d2:lǎn # 懒 0x61d3:ài # 懓 0x61d4:lǐn # 懔 0x61d5:yān # 懕 0x61d6:guō # 懖 0x61d7:xià # 懗 0x61d8:chì # 懘 0x61d9:yǔ,yú # 懙 0x61da:yìn # 懚 0x61db:dāi # 懛 0x61dc:mèng,méng,měng # 懜 0x61dd:ài,yì,nǐ # 懝 0x61de:méng,měng # 懞 0x61df:duì # 懟 0x61e0:qí,jī,jì # 懠 0x61e1:mǒ # 懡 0x61e2:lán,xiàn # 懢 0x61e3:mèn # 懣 0x61e4:chóu # 懤 0x61e5:zhì # 懥 0x61e6:nuò # 懦 0x61e7:nuò # 懧 0x61e8:yān # 懨 0x61e9:yǎng # 懩 0x61ea:bó # 懪 0x61eb:zhì # 懫 0x61ec:kuàng # 懬 0x61ed:kuǎng # 懭 0x61ee:yōu,yǒu # 懮 0x61ef:fū # 懯 0x61f0:liú,liǔ # 懰 0x61f1:miè # 懱 0x61f2:chéng # 懲 0x61f4:chàn # 懴 0x61f5:měng # 懵 0x61f6:lǎn # 懶 0x61f7:huái # 懷 0x61f8:xuán # 懸 0x61f9:ràng # 懹 0x61fa:chàn # 懺 0x61fb:jì # 懻 0x61fc:jù # 懼 0x61fd:huān # 懽 0x61fe:shè # 懾 0x61ff:yì # 懿 0x6200:liàn # 戀 0x6201:nǎn # 戁 0x6202:mí,mó # 戂 0x6203:tǎng # 戃 0x6204:jué # 戄 0x6205:gàng,zhuàng # 戅 0x6206:gàng,zhuàng # 戆 0x6207:gàng,zhuàng # 戇 0x6208:gē # 戈 0x6209:yuè # 戉 0x620a:wù # 戊 0x620b:jiān # 戋 0x620c:xū # 戌 0x620d:shù # 戍 0x620e:róng # 戎 0x620f:xì,hū # 戏 0x6210:chéng # 成 0x6211:wǒ # 我 0x6212:jiè # 戒 0x6213:gē # 戓 0x6214:jiān # 戔 0x6215:qiāng # 戕 0x6216:huò # 或 0x6217:qiāng,qiàng # 戗 0x6218:zhàn # 战 0x6219:dòng # 戙 0x621a:qī # 戚 0x621b:jiá # 戛 0x621c:dié # 戜 0x621d:zéi # 戝 0x621e:jiá # 戞 0x621f:jǐ # 戟 0x6220:zhí # 戠 0x6221:kān # 戡 0x6222:jí # 戢 0x6223:kuí # 戣 0x6224:gài # 戤 0x6225:děng # 戥 0x6226:zhàn # 戦 0x6227:qiāng,qiàng # 戧 0x6228:gē # 戨 0x6229:jiǎn # 戩 0x622a:jié # 截 0x622b:yù # 戫 0x622c:jiǎn # 戬 0x622d:yǎn # 戭 0x622e:lù # 戮 0x622f:xì,hū # 戯 0x6230:zhàn # 戰 0x6231:xì,hū # 戱 0x6232:xì,hū # 戲 0x6233:chuō # 戳 0x6234:dài # 戴 0x6235:qú # 戵 0x6236:hù # 戶 0x6237:hù # 户 0x6238:hù # 戸 0x6239:è # 戹 0x623a:shì # 戺 0x623b:tì # 戻 0x623c:mǎo # 戼 0x623d:hù # 戽 0x623e:lì # 戾 0x623f:fáng,páng # 房 0x6240:suǒ # 所 0x6241:biǎn,piān # 扁 0x6242:diàn # 扂 0x6243:jiōng # 扃 0x6244:shǎng,jiōng # 扄 0x6245:yí # 扅 0x6246:yǐ # 扆 0x6247:shàn,shān # 扇 0x6248:hù # 扈 0x6249:fēi # 扉 0x624a:yǎn # 扊 0x624b:shǒu # 手 0x624d:cái # 才 0x624e:zā,zhā,zhá # 扎 0x624f:qiú # 扏 0x6250:lè,lì,cái # 扐 0x6251:pū # 扑 0x6252:bā,pá # 扒 0x6253:dǎ,dá # 打 0x6254:rēng # 扔 0x6255:fǎn,fú # 払 0x6257:zài # 扗 0x6258:tuō # 托 0x6259:zhàng # 扙 0x625a:diǎo,dí,yuē,lì # 扚 0x625b:káng,gāng # 扛 0x625c:yū,wū # 扜 0x625d:yū,wū,kū # 扝 0x625e:hàn # 扞 0x625f:shēn # 扟 0x6260:chā # 扠 0x6261:tuō,chǐ,yǐ # 扡 0x6262:gǔ,xì,gē,jié # 扢 0x6263:kòu # 扣 0x6264:wù # 扤 0x6265:dèn # 扥 0x6266:qiān # 扦 0x6267:zhí # 执 0x6268:rèn # 扨 0x6269:kuò # 扩 0x626a:mén # 扪 0x626b:sǎo,sào # 扫 0x626c:yáng # 扬 0x626d:niǔ # 扭 0x626e:bàn # 扮 0x626f:chě # 扯 0x6270:rǎo # 扰 0x6271:xī,chā,qì # 扱 0x6272:qián,qín # 扲 0x6273:bān # 扳 0x6274:jiá # 扴 0x6275:yú # 扵 0x6276:fú # 扶 0x6277:bā,ào # 扷 0x6278:xī,zhé # 扸 0x6279:pī # 批 0x627a:zhǐ # 扺 0x627b:zhì,sǔn,kǎn # 扻 0x627c:è # 扼 0x627d:dèn # 扽 0x627e:zhǎo # 找 0x627f:chéng # 承 0x6280:jì # 技 0x6281:yǎn # 抁 0x6282:kuáng,wǎng,zài # 抂 0x6283:biàn # 抃 0x6284:chāo # 抄 0x6285:jū # 抅 0x6286:wěn # 抆 0x6287:hú,gǔ # 抇 0x6288:yuè # 抈 0x6289:jué # 抉 0x628a:bǎ,bà # 把 0x628b:qìn # 抋 0x628c:dǎn,shěn # 抌 0x628d:zhěng # 抍 0x628e:yǔn # 抎 0x628f:wán # 抏 0x6290:nè,nì,ruì,nà # 抐 0x6291:yì # 抑 0x6292:shū # 抒 0x6293:zhuā # 抓 0x6294:póu # 抔 0x6295:tóu # 投 0x6296:dǒu # 抖 0x6297:kàng # 抗 0x6298:zhē,zhé,shé # 折 0x6299:póu,pōu,fū # 抙 0x629a:fǔ # 抚 0x629b:pāo # 抛 0x629c:bá # 抜 0x629d:ǎo,ào,niù # 抝 0x629e:zé # 択 0x629f:tuán # 抟 0x62a0:kōu # 抠 0x62a1:lūn,lún # 抡 0x62a2:qiāng,qiǎng,chēng # 抢 0x62a4:hù # 护 0x62a5:bào # 报 0x62a6:bǐng # 抦 0x62a7:zhǐ,zhǎi # 抧 0x62a8:pēng # 抨 0x62a9:nán # 抩 0x62aa:bù,pū # 抪 0x62ab:pī # 披 0x62ac:tái # 抬 0x62ad:yǎo,tāo # 抭 0x62ae:zhěn # 抮 0x62af:zhā # 抯 0x62b0:yāng # 抰 0x62b1:bào # 抱 0x62b2:hē,hè,qiā # 抲 0x62b3:nǐ,ní # 抳 0x62b4:yè # 抴 0x62b5:dǐ # 抵 0x62b6:chì # 抶 0x62b7:pī,pēi # 抷 0x62b8:jiā # 抸 0x62b9:mǒ,mò,mā # 抹 0x62ba:mèi # 抺 0x62bb:chēn # 抻 0x62bc:yā # 押 0x62bd:chōu # 抽 0x62be:qū # 抾 0x62bf:mǐn # 抿 0x62c0:zhù # 拀 0x62c1:jiā,yá # 拁 0x62c2:fú,bì # 拂 0x62c3:zhǎ # 拃 0x62c4:zhǔ # 拄 0x62c5:dān,dàn,dǎn # 担 0x62c6:chāi,cā # 拆 0x62c7:mǔ # 拇 0x62c8:niān # 拈 0x62c9:lā,lá # 拉 0x62ca:fǔ # 拊 0x62cb:pāo # 拋 0x62cc:bàn,pàn # 拌 0x62cd:pāi # 拍 0x62ce:līn # 拎 0x62cf:ná # 拏 0x62d0:guǎi # 拐 0x62d1:qián # 拑 0x62d2:jù # 拒 0x62d3:tuò,tà,zhí # 拓 0x62d4:bá # 拔 0x62d5:tuō # 拕 0x62d6:tuō # 拖 0x62d7:ǎo,ào,niù # 拗 0x62d8:jū,gōu # 拘 0x62d9:zhuō # 拙 0x62da:pàn,pīn,fān # 拚 0x62db:zhāo # 招 0x62dc:bài # 拜 0x62dd:bài # 拝 0x62de:dǐ # 拞 0x62df:nǐ # 拟 0x62e0:jù # 拠 0x62e1:kuò # 拡 0x62e2:lǒng # 拢 0x62e3:jiǎn # 拣 0x62e5:yōng # 拥 0x62e6:lán # 拦 0x62e7:níng,nǐng,nìng # 拧 0x62e8:bō # 拨 0x62e9:zé,zhái # 择 0x62ea:qiān # 拪 0x62eb:hén # 拫 0x62ec:kuò,guā # 括 0x62ed:shì # 拭 0x62ee:jié,jiá # 拮 0x62ef:zhěng # 拯 0x62f0:nǐn # 拰 0x62f1:gǒng # 拱 0x62f2:gǒng # 拲 0x62f3:quán # 拳 0x62f4:shuān # 拴 0x62f5:cún,zùn # 拵 0x62f6:zā,zǎn # 拶 0x62f7:kǎo # 拷 0x62f8:yí,chǐ,hài # 拸 0x62f9:xié # 拹 0x62fa:cè,sè,chuò # 拺 0x62fb:huī # 拻 0x62fc:pīn # 拼 0x62fd:zhuài,zhuāi,yè # 拽 0x62fe:shí,shè # 拾 0x62ff:ná # 拿 0x6300:bāi # 挀 0x6301:chí # 持 0x6302:guà # 挂 0x6303:zhì # 挃 0x6304:kuò,guāng # 挄 0x6305:duò # 挅 0x6306:duǒ,duò # 挆 0x6307:zhǐ # 指 0x6308:qiè # 挈 0x6309:àn # 按 0x630a:nòng # 挊 0x630b:zhèn # 挋 0x630c:gé # 挌 0x630d:jiào # 挍 0x630e:kuà,kū # 挎 0x630f:dòng # 挏 0x6310:rú,ná # 挐 0x6311:tiāo,tiǎo # 挑 0x6312:liè # 挒 0x6313:zhā # 挓 0x6314:lǚ # 挔 0x6315:dié,shè # 挕 0x6316:wā # 挖 0x6317:jué # 挗 0x6319:jǔ # 挙 0x631a:zhì # 挚 0x631b:luán # 挛 0x631c:yà,yǎ # 挜 0x631d:zhuā,wō # 挝 0x631e:tà # 挞 0x631f:xié,jiā # 挟 0x6320:náo # 挠 0x6321:dǎng,dàng # 挡 0x6322:jiǎo # 挢 0x6323:zhèng,zhēng # 挣 0x6324:jǐ # 挤 0x6325:huī # 挥 0x6326:xián # 挦 0x6328:āi,ái # 挨 0x6329:tuō,shuì # 挩 0x632a:nuó # 挪 0x632b:cuò # 挫 0x632c:bó # 挬 0x632d:gěng # 挭 0x632e:tǐ,tì # 挮 0x632f:zhèn # 振 0x6330:chéng # 挰 0x6331:suō,shā # 挱 0x6332:suō,shā # 挲 0x6333:kēng,qiān # 挳 0x6334:měi # 挴 0x6335:nòng # 挵 0x6336:jú # 挶 0x6337:bàng,péng # 挷 0x6338:jiǎn # 挸 0x6339:yì # 挹 0x633a:tǐng # 挺 0x633b:shān # 挻 0x633c:ruó # 挼 0x633d:wǎn # 挽 0x633e:xié,jiā # 挾 0x633f:chā # 挿 0x6340:péng,féng # 捀 0x6341:jiǎo,kù # 捁 0x6342:wǔ # 捂 0x6343:jùn # 捃 0x6344:jiù,jū,qiú # 捄 0x6345:tǒng # 捅 0x6346:kǔn # 捆 0x6347:huò,chì # 捇 0x6348:tú,shū,chá # 捈 0x6349:zhuō # 捉 0x634a:póu,pōu,fū # 捊 0x634b:luō,lǚ # 捋 0x634c:bā # 捌 0x634d:hàn # 捍 0x634e:shāo,shào # 捎 0x634f:niē # 捏 0x6350:juān # 捐 0x6351:zè # 捑 0x6352:shù,sǒng,sōu # 捒 0x6353:yé,yú # 捓 0x6354:jué,zhuó # 捔 0x6355:bǔ # 捕 0x6356:wán # 捖 0x6357:bù,pú,zhì # 捗 0x6358:zùn # 捘 0x6359:yè # 捙 0x635a:zhāi # 捚 0x635b:lǚ # 捛 0x635c:sōu # 捜 0x635d:tuō,shuì # 捝 0x635e:lāo # 捞 0x635f:sǔn # 损 0x6360:bāng # 捠 0x6361:jiǎn # 捡 0x6362:huàn # 换 0x6363:dǎo # 捣 0x6365:wàn,wǎn,wān,yù # 捥 0x6366:qín # 捦 0x6367:pěng # 捧 0x6368:shě # 捨 0x6369:liè # 捩 0x636a:mín # 捪 0x636b:mén # 捫 0x636c:fǔ,fù,bǔ # 捬 0x636d:bǎi # 捭 0x636e:jù,jū # 据 0x636f:dáo # 捯 0x6370:wǒ,luò,luǒ # 捰 0x6371:ái # 捱 0x6372:juǎn,quán # 捲 0x6373:yuè # 捳 0x6374:zǒng # 捴 0x6375:chēn # 捵 0x6376:chuí # 捶 0x6377:jié # 捷 0x6378:tū # 捸 0x6379:bèn # 捹 0x637a:nà # 捺 0x637b:niǎn,niē # 捻 0x637c:ruó,wěi,ré # 捼 0x637d:zuó # 捽 0x637e:wò,xiá # 捾 0x637f:qī # 捿 0x6380:xiān # 掀 0x6381:chéng # 掁 0x6382:diān # 掂 0x6383:sǎo,sào # 掃 0x6384:lūn,lún # 掄 0x6385:qìng,qiàn # 掅 0x6386:gāng # 掆 0x6387:duō # 掇 0x6388:shòu # 授 0x6389:diào # 掉 0x638a:pǒu,póu # 掊 0x638b:dǐ # 掋 0x638c:zhǎng # 掌 0x638d:hùn # 掍 0x638e:jǐ # 掎 0x638f:tāo # 掏 0x6390:qiā # 掐 0x6391:qí # 掑 0x6392:pái,pǎi # 排 0x6393:shū # 掓 0x6394:qiān,wàn # 掔 0x6395:líng # 掕 0x6396:yè,yē # 掖 0x6397:yà,yǎ # 掗 0x6398:jué # 掘 0x6399:zhēng,zhèng # 掙 0x639a:liǎng # 掚 0x639b:guà # 掛 0x639c:nǐ,niè,yì # 掜 0x639d:huò,xù # 掝 0x639e:shàn,yàn,yǎn # 掞 0x639f:zhěng,dìng # 掟 0x63a0:lüè # 掠 0x63a1:cǎi # 採 0x63a2:tàn # 探 0x63a3:chè # 掣 0x63a4:bīng # 掤 0x63a5:jiē # 接 0x63a6:tì # 掦 0x63a7:kòng # 控 0x63a8:tuī # 推 0x63a9:yǎn # 掩 0x63aa:cuò # 措 0x63ab:zōu,zhōu,chōu # 掫 0x63ac:jū # 掬 0x63ad:tiàn # 掭 0x63ae:qián # 掮 0x63af:kèn # 掯 0x63b0:bāi # 掰 0x63b1:pá # 掱 0x63b2:jiē # 掲 0x63b3:lǔ # 掳 0x63b4:guó # 掴 0x63b7:zhì # 掷 0x63b8:dǎn,shàn # 掸 0x63ba:chān,xiān,càn,shǎn # 掺 0x63bb:sāo # 掻 0x63bc:guàn # 掼 0x63bd:pèng # 掽 0x63be:yuàn # 掾 0x63bf:nuò # 掿 0x63c0:jiǎn # 揀 0x63c1:zhēng,kēng # 揁 0x63c2:jiū,yóu # 揂 0x63c3:jiǎn,jiān # 揃 0x63c4:yú # 揄 0x63c5:yán # 揅 0x63c6:kuí # 揆 0x63c7:nǎn # 揇 0x63c8:hōng # 揈 0x63c9:róu # 揉 0x63ca:pì,chè # 揊 0x63cb:wēi # 揋 0x63cc:sāi,zǒng,cāi # 揌 0x63cd:zòu # 揍 0x63ce:xuān # 揎 0x63cf:miáo # 描 0x63d0:tí,dī,dǐ # 提 0x63d1:niē # 揑 0x63d2:chā # 插 0x63d3:shì # 揓 0x63d4:zǒng,sōng # 揔 0x63d5:zhèn,zhēn # 揕 0x63d6:yī # 揖 0x63d7:xún # 揗 0x63d8:huáng,yóng # 揘 0x63d9:biǎn # 揙 0x63da:yáng # 揚 0x63db:huàn # 換 0x63dc:yǎn # 揜 0x63dd:zǎn,zuàn # 揝 0x63de:ǎn # 揞 0x63df:xū,jū # 揟 0x63e0:yà # 揠 0x63e1:wò # 握 0x63e2:ké,qiā # 揢 0x63e3:chuǎi,chuài,chuāi,tuán,zhuī # 揣 0x63e4:jí # 揤 0x63e5:tì,dì # 揥 0x63e6:là,lá # 揦 0x63e7:là # 揧 0x63e8:chéng # 揨 0x63e9:kāi # 揩 0x63ea:jiū # 揪 0x63eb:jiū # 揫 0x63ec:tú # 揬 0x63ed:jiē,qì # 揭 0x63ee:huī # 揮 0x63ef:gèn # 揯 0x63f0:chòng,dǒng # 揰 0x63f1:xiāo # 揱 0x63f2:shé,dié,yè # 揲 0x63f3:xiē # 揳 0x63f4:yuán # 援 0x63f5:qián,jiàn,jiǎn # 揵 0x63f6:yé # 揶 0x63f7:chā # 揷 0x63f8:zhā # 揸 0x63f9:bēi # 揹 0x63fa:yáo # 揺 0x63fd:lǎn # 揽 0x63fe:wèn # 揾 0x63ff:qìn # 揿 0x6400:chān # 搀 0x6401:gē,gé # 搁 0x6402:lǒu,lōu # 搂 0x6403:zǒng # 搃 0x6404:gèn # 搄 0x6405:jiǎo # 搅 0x6406:gòu # 搆 0x6407:qìn # 搇 0x6408:róng # 搈 0x6409:què # 搉 0x640a:chōu,zǒu # 搊 0x640b:chuāi # 搋 0x640c:zhǎn # 搌 0x640d:sǔn # 損 0x640e:sūn # 搎 0x640f:bó # 搏 0x6410:chù # 搐 0x6411:róng,náng,nǎng # 搑 0x6412:bàng,péng # 搒 0x6413:cuō # 搓 0x6414:sāo # 搔 0x6415:kē,è # 搕 0x6416:yáo # 搖 0x6417:dǎo # 搗 0x6418:zhī # 搘 0x6419:nù,nuò,nòu # 搙 0x641a:lā,xié,xiàn # 搚 0x641b:jiān # 搛 0x641c:sōu # 搜 0x641d:qiǔ # 搝 0x641e:gǎo # 搞 0x641f:xiǎn,xiān # 搟 0x6420:shuò # 搠 0x6421:sǎng # 搡 0x6422:jìn # 搢 0x6423:miè # 搣 0x6424:è # 搤 0x6425:chuí # 搥 0x6426:nuò # 搦 0x6427:shān # 搧 0x6428:tà # 搨 0x6429:jié,zhé # 搩 0x642a:táng # 搪 0x642b:pán,bān,pó # 搫 0x642c:bān # 搬 0x642d:dā # 搭 0x642e:lì # 搮 0x642f:tāo # 搯 0x6430:hú # 搰 0x6431:zhì,nái # 搱 0x6432:wā,wǎ,wà # 搲 0x6433:huá # 搳 0x6434:qiān # 搴 0x6435:wèn # 搵 0x6436:qiāng,qiǎng,chēng # 搶 0x6437:tián,shēn # 搷 0x6438:zhēn # 搸 0x6439:è # 搹 0x643a:xié # 携 0x643b:ná,nuò # 搻 0x643c:quán # 搼 0x643d:chá # 搽 0x643e:zhà # 搾 0x643f:gé # 搿 0x6440:wǔ # 摀 0x6441:èn # 摁 0x6442:shè # 摂 0x6443:gāng # 摃 0x6444:shè,niè # 摄 0x6445:shū # 摅 0x6446:bǎi # 摆 0x6447:yáo # 摇 0x6448:bìn # 摈 0x6449:sōu # 摉 0x644a:tān # 摊 0x644b:sà,shā,shǎi # 摋 0x644c:chǎn,sùn # 摌 0x644d:suō # 摍 0x644e:jiū,liú,liáo,jiǎo,náo # 摎 0x644f:chōng # 摏 0x6450:chuāng # 摐 0x6451:guó,guāi # 摑 0x6452:bìng # 摒 0x6453:féng,pěng # 摓 0x6454:shuāi # 摔 0x6455:dì,tú,zhí # 摕 0x6456:qì,jì,chá # 摖 0x6458:zhāi # 摘 0x6459:liǎn,liàn # 摙 0x645a:chēng # 摚 0x645b:chī # 摛 0x645c:guàn # 摜 0x645d:lù # 摝 0x645e:luò # 摞 0x645f:lǒu,lōu # 摟 0x6460:zǒng # 摠 0x6461:gài,xì # 摡 0x6462:hù,chū # 摢 0x6463:zhā # 摣 0x6464:qiāng # 摤 0x6465:tàng # 摥 0x6466:huà # 摦 0x6467:cuī # 摧 0x6468:zhì,nái # 摨 0x6469:mó,mā # 摩 0x646a:jiāng,qiàng # 摪 0x646b:guī # 摫 0x646c:yǐng # 摬 0x646d:zhí # 摭 0x646e:áo,qiáo # 摮 0x646f:zhì # 摯 0x6470:niè,chè # 摰 0x6471:mán,màn # 摱 0x6472:chàn,cán # 摲 0x6473:kōu # 摳 0x6474:chū # 摴 0x6475:sè,mí,sù # 摵 0x6476:tuán # 摶 0x6477:jiǎo,chāo # 摷 0x6478:mō # 摸 0x6479:mó # 摹 0x647a:zhé # 摺 0x647b:chān,xiān,càn,shǎn # 摻 0x647c:kēng,qiān # 摼 0x647d:biào,biāo # 摽 0x647e:jiàng # 摾 0x647f:yáo # 摿 0x6480:gòu # 撀 0x6481:qiān # 撁 0x6482:liào # 撂 0x6483:jī # 撃 0x6484:yīng # 撄 0x6485:juē,jué # 撅 0x6486:piē # 撆 0x6487:piē,piě # 撇 0x6488:lāo # 撈 0x6489:dūn # 撉 0x648a:xiàn # 撊 0x648b:ruán # 撋 0x648c:guì # 撌 0x648d:zǎn,zān,zēn,qián # 撍 0x648e:yī # 撎 0x648f:xián # 撏 0x6490:chēng # 撐 0x6491:chēng # 撑 0x6492:sā,sǎ # 撒 0x6493:náo # 撓 0x6494:hòng # 撔 0x6495:sī # 撕 0x6496:hàn # 撖 0x6497:héng,guàng # 撗 0x6498:dā # 撘 0x6499:zǔn # 撙 0x649a:niǎn # 撚 0x649b:lǐn # 撛 0x649c:zhěng,chéng # 撜 0x649d:huī,wéi # 撝 0x649e:zhuàng # 撞 0x649f:jiǎo # 撟 0x64a0:jǐ # 撠 0x64a1:cāo # 撡 0x64a2:dǎn # 撢 0x64a3:dǎn,shàn # 撣 0x64a4:chè # 撤 0x64a5:bō # 撥 0x64a6:chě # 撦 0x64a7:juē # 撧 0x64a8:xiāo,sōu # 撨 0x64a9:liāo,liáo # 撩 0x64aa:bèn # 撪 0x64ab:fǔ # 撫 0x64ac:qiào # 撬 0x64ad:bō # 播 0x64ae:cuō,zuǒ # 撮 0x64af:zhuó # 撯 0x64b0:zhuàn # 撰 0x64b1:wěi,tuǒ # 撱 0x64b2:pū # 撲 0x64b3:qìn # 撳 0x64b4:dūn # 撴 0x64b5:niǎn # 撵 0x64b7:xié # 撷 0x64b8:lū # 撸 0x64b9:jiǎo # 撹 0x64ba:cuān # 撺 0x64bb:tà # 撻 0x64bc:hàn # 撼 0x64bd:qiào,yāo,jī # 撽 0x64be:zhuā,wō # 撾 0x64bf:jiǎn # 撿 0x64c0:gǎn # 擀 0x64c1:yōng # 擁 0x64c2:léi,lèi # 擂 0x64c3:nǎng # 擃 0x64c4:lǔ # 擄 0x64c5:shàn # 擅 0x64c6:zhuó # 擆 0x64c7:zé,zhái # 擇 0x64c8:pǔ # 擈 0x64c9:chuò # 擉 0x64ca:jī # 擊 0x64cb:dǎng,dàng # 擋 0x64cc:sè # 擌 0x64cd:cāo # 操 0x64ce:qíng # 擎 0x64cf:qíng,jǐng # 擏 0x64d0:huàn # 擐 0x64d1:jiē # 擑 0x64d2:qín # 擒 0x64d3:kuǎi # 擓 0x64d4:dān,dàn # 擔 0x64d5:xié # 擕 0x64d6:qiā,jiā,yè # 擖 0x64d7:pǐ,bò # 擗 0x64d8:bò,bāi # 擘 0x64d9:ào # 擙 0x64da:jù,jū # 據 0x64db:yè # 擛 0x64de:sòu,sǒu # 擞 0x64df:mí # 擟 0x64e0:jǐ # 擠 0x64e1:tái # 擡 0x64e2:zhuó # 擢 0x64e3:dǎo # 擣 0x64e4:xǐng # 擤 0x64e5:lǎn # 擥 0x64e6:cā # 擦 0x64e7:jǔ # 擧 0x64e8:yē # 擨 0x64e9:rǔ # 擩 0x64ea:yè # 擪 0x64eb:yè # 擫 0x64ec:nǐ # 擬 0x64ed:huò # 擭 0x64ee:jié # 擮 0x64ef:bìn # 擯 0x64f0:níng,nǐng,nìng # 擰 0x64f1:gē,gé # 擱 0x64f2:zhì # 擲 0x64f3:zhì,jié # 擳 0x64f4:kuò # 擴 0x64f5:mó # 擵 0x64f6:jiàn # 擶 0x64f7:xié # 擷 0x64f8:liè,là # 擸 0x64f9:tān # 擹 0x64fa:bǎi # 擺 0x64fb:sòu,sǒu # 擻 0x64fc:lū # 擼 0x64fd:lì,luò,yuè # 擽 0x64fe:rǎo # 擾 0x64ff:tī,zhì,zhāi # 擿 0x6500:pān # 攀 0x6501:yǎng # 攁 0x6502:léi,lèi # 攂 0x6503:cā,sǎ # 攃 0x6504:shū # 攄 0x6505:zǎn # 攅 0x6506:niǎn # 攆 0x6507:xiǎn # 攇 0x6508:jùn,pèi # 攈 0x6509:huō # 攉 0x650a:lì,luò # 攊 0x650b:là,lài # 攋 0x650c:huàn # 攌 0x650d:yíng # 攍 0x650e:lú,luó # 攎 0x650f:lǒng # 攏 0x6510:qiān # 攐 0x6511:qiān # 攑 0x6512:zǎn,cuán # 攒 0x6513:qiān # 攓 0x6514:lán # 攔 0x6515:xiān,jiān # 攕 0x6516:yīng # 攖 0x6517:méi # 攗 0x6518:rǎng # 攘 0x6519:chān # 攙 0x651b:cuān # 攛 0x651c:xié # 攜 0x651d:shè,niè # 攝 0x651e:luó # 攞 0x651f:jùn # 攟 0x6520:mí,mǐ,mó # 攠 0x6521:chī # 攡 0x6522:zǎn,cuán # 攢 0x6523:luán # 攣 0x6524:tān # 攤 0x6525:zuàn # 攥 0x6526:lì,shài # 攦 0x6527:diān # 攧 0x6528:wā # 攨 0x6529:dǎng # 攩 0x652a:jiǎo # 攪 0x652b:jué # 攫 0x652c:lǎn # 攬 0x652d:lì,luǒ # 攭 0x652e:nǎng # 攮 0x652f:zhī # 支 0x6530:guì # 攰 0x6531:guǐ,guì # 攱 0x6532:qī,yǐ,jī # 攲 0x6533:xún # 攳 0x6534:pū # 攴 0x6535:pū # 攵 0x6536:shōu # 收 0x6537:kǎo # 攷 0x6538:yōu # 攸 0x6539:gǎi # 改 0x653a:yǐ # 攺 0x653b:gōng # 攻 0x653c:gān,hàn # 攼 0x653d:bān # 攽 0x653e:fàng # 放 0x653f:zhèng # 政 0x6540:pò # 敀 0x6541:diān # 敁 0x6542:kòu # 敂 0x6543:mǐn # 敃 0x6544:wù,móu # 敄 0x6545:gù # 故 0x6546:hé # 敆 0x6547:cè # 敇 0x6548:xiào # 效 0x6549:mǐ # 敉 0x654a:chù,shōu # 敊 0x654b:gé,guó,è # 敋 0x654c:dí # 敌 0x654d:xù # 敍 0x654e:jiào,jiāo # 敎 0x654f:mǐn # 敏 0x6550:chén # 敐 0x6551:jiù # 救 0x6552:shēn # 敒 0x6553:duó,duì # 敓 0x6554:yǔ # 敔 0x6555:chì # 敕 0x6556:áo # 敖 0x6557:bài # 敗 0x6558:xù # 敘 0x6559:jiào,jiāo # 教 0x655a:duó,duì # 敚 0x655b:liǎn # 敛 0x655c:niè # 敜 0x655d:bì # 敝 0x655e:chǎng # 敞 0x655f:diǎn # 敟 0x6560:duō,què # 敠 0x6561:yì # 敡 0x6562:gǎn # 敢 0x6563:sàn,sǎn # 散 0x6564:kě # 敤 0x6565:yàn # 敥 0x6566:dūn,duì # 敦 0x6567:qī,yǐ,jī # 敧 0x6568:tǒu # 敨 0x6569:xiào,xué # 敩 0x656a:duō,què # 敪 0x656b:jiǎo # 敫 0x656c:jìng # 敬 0x656d:yáng # 敭 0x656e:xiá # 敮 0x656f:mǐn # 敯 0x6570:shù,shǔ,shuò # 数 0x6571:ái,zhú # 敱 0x6572:qiāo # 敲 0x6573:ái # 敳 0x6574:zhěng # 整 0x6575:dí # 敵 0x6576:chén # 敶 0x6577:fū # 敷 0x6578:shù,shǔ,shuò # 數 0x6579:liáo # 敹 0x657a:qū # 敺 0x657b:xiòng,xuàn # 敻 0x657c:yǐ # 敼 0x657d:jiǎo # 敽 0x657f:jiǎo # 敿 0x6580:zhuó,zhú # 斀 0x6581:yì,dù # 斁 0x6582:liǎn # 斂 0x6583:bì # 斃 0x6584:lí,tái # 斄 0x6585:xiào # 斅 0x6586:xiào # 斆 0x6587:wén # 文 0x6588:xué # 斈 0x6589:qí # 斉 0x658a:qí # 斊 0x658b:zhāi # 斋 0x658c:bīn # 斌 0x658d:jué,jiào # 斍 0x658e:zhāi # 斎 0x6590:fěi,fēi # 斐 0x6591:bān # 斑 0x6592:bān # 斒 0x6593:lán # 斓 0x6594:yǔ,zhōng # 斔 0x6595:lán # 斕 0x6596:wěi,mén # 斖 0x6597:dǒu,dòu # 斗 0x6598:shēng # 斘 0x6599:liào # 料 0x659a:jiǎ # 斚 0x659b:hú # 斛 0x659c:xié # 斜 0x659d:jiǎ # 斝 0x659e:yǔ # 斞 0x659f:zhēn # 斟 0x65a0:jiào # 斠 0x65a1:wò,guǎn # 斡 0x65a2:tǒu,tiǎo # 斢 0x65a3:dòu # 斣 0x65a4:jīn # 斤 0x65a5:chì # 斥 0x65a6:yín,zhì # 斦 0x65a7:fǔ # 斧 0x65a8:qiāng # 斨 0x65a9:zhǎn # 斩 0x65aa:qú # 斪 0x65ab:zhuó # 斫 0x65ac:zhǎn # 斬 0x65ad:duàn # 断 0x65ae:zhuó # 斮 0x65af:sī # 斯 0x65b0:xīn # 新 0x65b1:zhuó # 斱 0x65b2:zhuó # 斲 0x65b3:qín # 斳 0x65b4:lín # 斴 0x65b5:zhuó # 斵 0x65b6:chù # 斶 0x65b7:duàn # 斷 0x65b8:zhú # 斸 0x65b9:fāng # 方 0x65ba:chǎn,jiè # 斺 0x65bb:háng # 斻 0x65bc:yú,wū # 於 0x65bd:shī # 施 0x65be:pèi # 斾 0x65bf:liú,yóu # 斿 0x65c1:páng,bàng # 旁 0x65c2:qí # 旂 0x65c3:zhān # 旃 0x65c4:máo,mào # 旄 0x65c5:lǚ # 旅 0x65c6:pèi # 旆 0x65c7:pī,bì # 旇 0x65c8:liú # 旈 0x65c9:fū # 旉 0x65ca:fǎng # 旊 0x65cb:xuán,xuàn # 旋 0x65cc:jīng # 旌 0x65cd:jīng # 旍 0x65ce:nǐ # 旎 0x65cf:zú # 族 0x65d0:zhào # 旐 0x65d1:yǐ # 旑 0x65d2:liú # 旒 0x65d3:shāo # 旓 0x65d4:jiàn # 旔 0x65d6:yǐ # 旖 0x65d7:qí # 旗 0x65d8:zhì # 旘 0x65d9:fān # 旙 0x65da:piāo # 旚 0x65db:fān # 旛 0x65dc:zhān # 旜 0x65dd:kuài # 旝 0x65de:suì # 旞 0x65df:yú # 旟 0x65e0:wú,mó # 无 0x65e1:jì # 旡 0x65e2:jì # 既 0x65e3:jì # 旣 0x65e4:huò # 旤 0x65e5:rì # 日 0x65e6:dàn # 旦 0x65e7:jiù # 旧 0x65e8:zhǐ # 旨 0x65e9:zǎo # 早 0x65ea:xié # 旪 0x65eb:tiāo # 旫 0x65ec:xún # 旬 0x65ed:xù # 旭 0x65ee:gā # 旮 0x65ef:lá # 旯 0x65f0:gàn,hàn # 旰 0x65f1:hàn # 旱 0x65f2:tái,yīng # 旲 0x65f3:dì,dí,de # 旳 0x65f4:xù,xū # 旴 0x65f5:chǎn # 旵 0x65f6:shí # 时 0x65f7:kuàng # 旷 0x65f8:yáng # 旸 0x65f9:shí # 旹 0x65fa:wàng # 旺 0x65fb:mín # 旻 0x65fc:mín # 旼 0x65fd:tūn,zhùn # 旽 0x65fe:chūn # 旾 0x65ff:wù,wǔ # 旿 0x6600:yún # 昀 0x6601:bèi # 昁 0x6602:áng # 昂 0x6603:zè # 昃 0x6604:bǎn # 昄 0x6605:jié # 昅 0x6606:kūn # 昆 0x6607:shēng # 昇 0x6608:hù # 昈 0x6609:fǎng # 昉 0x660a:hào # 昊 0x660b:guì # 昋 0x660c:chāng # 昌 0x660d:xuān # 昍 0x660e:míng # 明 0x660f:hūn # 昏 0x6610:fēn # 昐 0x6611:qǐn # 昑 0x6612:hū # 昒 0x6613:yì # 易 0x6614:xī # 昔 0x6615:xīn # 昕 0x6616:yán # 昖 0x6617:zè # 昗 0x6618:fǎng # 昘 0x6619:tán # 昙 0x661a:shèn # 昚 0x661b:jù # 昛 0x661c:yáng # 昜 0x661d:zǎn # 昝 0x661e:bǐng # 昞 0x661f:xīng # 星 0x6620:yìng # 映 0x6621:xuàn # 昡 0x6622:pò # 昢 0x6623:zhěn # 昣 0x6624:líng # 昤 0x6625:chūn # 春 0x6626:hào # 昦 0x6627:mèi # 昧 0x6628:zuó # 昨 0x6629:mò # 昩 0x662a:biàn # 昪 0x662b:xù # 昫 0x662c:hūn # 昬 0x662d:zhāo # 昭 0x662e:zòng # 昮 0x662f:shì # 是 0x6630:shì # 昰 0x6631:yù # 昱 0x6632:fèi # 昲 0x6633:dié,yì # 昳 0x6634:mǎo # 昴 0x6635:nì # 昵 0x6636:chǎng # 昶 0x6637:wēn # 昷 0x6638:dōng # 昸 0x6639:ǎi # 昹 0x663a:bǐng # 昺 0x663b:áng # 昻 0x663c:zhòu # 昼 0x663d:lóng # 昽 0x663e:xiǎn # 显 0x663f:kuàng # 昿 0x6640:tiǎo # 晀 0x6641:cháo # 晁 0x6642:shí # 時 0x6643:huǎng,huàng # 晃 0x6644:huǎng # 晄 0x6645:xuān # 晅 0x6646:kuí # 晆 0x6647:xù,kuā # 晇 0x6648:jiǎo # 晈 0x6649:jìn # 晉 0x664a:zhì # 晊 0x664b:jìn # 晋 0x664c:shǎng # 晌 0x664d:tóng # 晍 0x664e:hǒng # 晎 0x664f:yàn # 晏 0x6650:gāi # 晐 0x6651:xiǎng # 晑 0x6652:shài # 晒 0x6653:xiǎo # 晓 0x6654:yè # 晔 0x6655:yùn,yūn # 晕 0x6656:huī # 晖 0x6657:hán # 晗 0x6658:hàn # 晘 0x6659:jùn # 晙 0x665a:wǎn # 晚 0x665b:xiàn # 晛 0x665c:kūn # 晜 0x665d:zhòu # 晝 0x665e:xī # 晞 0x665f:shèng,chéng # 晟 0x6660:shèng # 晠 0x6661:bū # 晡 0x6662:zhé # 晢 0x6663:zhé # 晣 0x6664:wù # 晤 0x6665:wǎn,hàn # 晥 0x6666:huì # 晦 0x6667:hào # 晧 0x6668:chén # 晨 0x6669:wǎn # 晩 0x666a:tiǎn # 晪 0x666b:zhuó # 晫 0x666c:zuì # 晬 0x666d:zhǒu # 晭 0x666e:pǔ # 普 0x666f:jǐng,yǐng # 景 0x6670:xī # 晰 0x6671:shǎn # 晱 0x6672:nǐ # 晲 0x6673:xī # 晳 0x6674:qíng # 晴 0x6675:qǐ,dù # 晵 0x6676:jīng # 晶 0x6677:guǐ # 晷 0x6678:zhěng # 晸 0x6679:yì # 晹 0x667a:zhì # 智 0x667b:àn,ǎn,yǎn # 晻 0x667c:wǎn # 晼 0x667d:lín # 晽 0x667e:liàng # 晾 0x667f:chēng # 晿 0x6680:wǎng,wàng # 暀 0x6681:xiǎo # 暁 0x6682:zàn # 暂 0x6684:xuān # 暄 0x6685:xuǎn,gèng # 暅 0x6686:yí # 暆 0x6687:xiá # 暇 0x6688:yùn,yūn # 暈 0x6689:huī # 暉 0x668a:xǔ # 暊 0x668b:mǐn,mín # 暋 0x668c:kuí # 暌 0x668d:yē # 暍 0x668e:yìng # 暎 0x668f:shǔ,dǔ # 暏 0x6690:wěi # 暐 0x6691:shǔ # 暑 0x6692:qíng # 暒 0x6693:mào # 暓 0x6694:nán # 暔 0x6695:jiǎn,lán # 暕 0x6696:nuǎn # 暖 0x6697:àn # 暗 0x6698:yáng # 暘 0x6699:chūn # 暙 0x669a:yáo # 暚 0x669b:suǒ # 暛 0x669c:pǔ # 暜 0x669d:míng # 暝 0x669e:jiǎo # 暞 0x669f:kǎi # 暟 0x66a0:hào,gǎo # 暠 0x66a1:wěng # 暡 0x66a2:chàng # 暢 0x66a3:qì # 暣 0x66a4:hào # 暤 0x66a5:yàn # 暥 0x66a6:lì # 暦 0x66a7:ài # 暧 0x66a8:jì # 暨 0x66a9:jì # 暩 0x66aa:mèn # 暪 0x66ab:zàn # 暫 0x66ac:xiè # 暬 0x66ad:hào # 暭 0x66ae:mù # 暮 0x66af:mù # 暯 0x66b0:cōng # 暰 0x66b1:nì # 暱 0x66b2:zhāng # 暲 0x66b3:huì # 暳 0x66b4:bào,pù # 暴 0x66b5:hàn # 暵 0x66b6:xuán # 暶 0x66b7:chuán # 暷 0x66b8:liáo # 暸 0x66b9:xiān # 暹 0x66ba:tǎn # 暺 0x66bb:jǐng # 暻 0x66bc:piē # 暼 0x66bd:lín # 暽 0x66be:tūn # 暾 0x66bf:xī,xǐ # 暿 0x66c0:yì # 曀 0x66c1:jì # 曁 0x66c2:huàng # 曂 0x66c3:dài # 曃 0x66c4:yè # 曄 0x66c5:yè # 曅 0x66c6:lì # 曆 0x66c7:tán # 曇 0x66c8:tóng # 曈 0x66c9:xiǎo # 曉 0x66ca:fèi # 曊 0x66cb:shěn # 曋 0x66cc:zhào # 曌 0x66cd:hào # 曍 0x66ce:yì # 曎 0x66cf:xiàng # 曏 0x66d0:xīng # 曐 0x66d1:shēn # 曑 0x66d2:jiǎo # 曒 0x66d3:bào # 曓 0x66d4:jìng # 曔 0x66d5:yàn # 曕 0x66d6:ài # 曖 0x66d7:yè # 曗 0x66d8:rú # 曘 0x66d9:shǔ # 曙 0x66da:méng # 曚 0x66db:xūn # 曛 0x66dc:yào # 曜 0x66dd:pù,bào # 曝 0x66de:lì # 曞 0x66df:chén # 曟 0x66e0:kuàng # 曠 0x66e1:dié # 曡 0x66e3:yàn # 曣 0x66e4:huò # 曤 0x66e5:lú # 曥 0x66e6:xī # 曦 0x66e7:róng # 曧 0x66e8:lóng # 曨 0x66e9:nǎng # 曩 0x66ea:luǒ # 曪 0x66eb:luán # 曫 0x66ec:shài # 曬 0x66ed:tǎng # 曭 0x66ee:yǎn # 曮 0x66ef:zhú # 曯 0x66f0:yuē # 曰 0x66f1:yuē # 曱 0x66f2:qū,qǔ # 曲 0x66f3:yè # 曳 0x66f4:gēng,gèng # 更 0x66f5:yè # 曵 0x66f6:hū,hù # 曶 0x66f7:hé # 曷 0x66f8:shū # 書 0x66f9:cáo # 曹 0x66fa:cáo # 曺 0x66fc:màn # 曼 0x66fd:zēng,céng # 曽 0x66fe:zēng,céng # 曾 0x66ff:tì # 替 0x6700:zuì # 最 0x6701:cǎn,qián,jiàn # 朁 0x6702:xù # 朂 0x6703:huì,kuài # 會 0x6704:yǐn # 朄 0x6705:qiè,hé # 朅 0x6706:fēn # 朆 0x6707:bì,pí # 朇 0x6708:yuè # 月 0x6709:yǒu,yòu # 有 0x670a:ruǎn # 朊 0x670b:péng # 朋 0x670c:fén,bān # 朌 0x670d:fú,fù # 服 0x670e:líng # 朎 0x670f:fěi,kū # 朏 0x6710:qú,xù,chǔn # 朐 0x6712:nǜ,gǎ # 朒 0x6713:tiǎo # 朓 0x6714:shuò # 朔 0x6715:zhèn # 朕 0x6716:lǎng # 朖 0x6717:lǎng # 朗 0x6718:juān,zuī # 朘 0x6719:míng # 朙 0x671a:huāng,máng,wáng # 朚 0x671b:wàng # 望 0x671c:tūn # 朜 0x671d:zhāo,cháo # 朝 0x671e:jī # 朞 0x671f:qī,jī # 期 0x6720:yīng # 朠 0x6721:zōng # 朡 0x6722:wàng # 朢 0x6723:tóng,chuáng # 朣 0x6724:lǎng # 朤 0x6726:méng # 朦 0x6727:lóng # 朧 0x6728:mù # 木 0x6729:tin # 朩 0x672a:wèi # 未 0x672b:mò # 末 0x672c:běn # 本 0x672d:zhá # 札 0x672e:shù,shú,zhú # 朮 0x672f:shù,shú,zhú # 术 0x6731:zhū,shú # 朱 0x6732:rén # 朲 0x6733:bā # 朳 0x6734:pǔ,pò,pō,piáo # 朴 0x6735:duǒ # 朵 0x6736:duǒ # 朶 0x6737:dāo,tiáo,mù # 朷 0x6738:lì # 朸 0x6739:qiú,guǐ # 朹 0x673a:jī # 机 0x673b:jiū # 朻 0x673c:bǐ # 朼 0x673d:xiǔ # 朽 0x673e:chéng,chēng # 朾 0x673f:cì # 朿 0x6740:shā # 杀 0x6742:zá # 杂 0x6743:quán # 权 0x6744:qiān # 杄 0x6745:yú,wū # 杅 0x6746:gān,gǎn # 杆 0x6747:wū # 杇 0x6748:chā,chà # 杈 0x6749:shān,shā # 杉 0x674a:xún # 杊 0x674b:fán # 杋 0x674c:wù # 杌 0x674d:zǐ # 杍 0x674e:lǐ # 李 0x674f:xìng # 杏 0x6750:cái # 材 0x6751:cūn # 村 0x6752:rèn,ér # 杒 0x6753:sháo,biāo # 杓 0x6754:tuō,zhé # 杔 0x6755:dì,duò # 杕 0x6756:zhàng # 杖 0x6757:máng # 杗 0x6758:chì # 杘 0x6759:yì # 杙 0x675a:gū,gài # 杚 0x675b:gōng # 杛 0x675c:dù # 杜 0x675d:yí,lì,lí,duò,tuò # 杝 0x675e:qǐ # 杞 0x675f:shù # 束 0x6760:gàng,gāng # 杠 0x6761:tiáo,tiāo # 条 0x6765:lái # 来 0x6767:máng # 杧 0x6768:yáng # 杨 0x6769:mà,mǎ # 杩 0x676a:miǎo # 杪 0x676b:sì,zhǐ,xǐ # 杫 0x676c:yuán,wán # 杬 0x676d:háng # 杭 0x676e:fèi,bèi # 杮 0x676f:bēi # 杯 0x6770:jié # 杰 0x6771:dōng # 東 0x6772:gǎo # 杲 0x6773:yǎo # 杳 0x6774:xiān # 杴 0x6775:chǔ # 杵 0x6776:chūn # 杶 0x6777:pá # 杷 0x6778:shū,duì # 杸 0x6779:huà # 杹 0x677a:xīn # 杺 0x677b:niǔ,chǒu # 杻 0x677c:zhù # 杼 0x677d:chǒu # 杽 0x677e:sōng # 松 0x677f:bǎn # 板 0x6780:sōng # 枀 0x6781:jí # 极 0x6782:wò,yuè # 枂 0x6783:jìn # 枃 0x6784:gòu # 构 0x6785:jī # 枅 0x6786:máo # 枆 0x6787:pí # 枇 0x6788:pī,mì # 枈 0x6789:wǎng # 枉 0x678a:àng # 枊 0x678b:fāng,bìng # 枋 0x678c:fén # 枌 0x678d:yì # 枍 0x678e:fú,fū # 枎 0x678f:nán # 枏 0x6790:xī # 析 0x6791:hù,dǐ # 枑 0x6792:yā # 枒 0x6793:dōu # 枓 0x6794:xín # 枔 0x6795:zhěn # 枕 0x6796:yǎo,yāo # 枖 0x6797:lín # 林 0x6798:ruì # 枘 0x6799:ě,è # 枙 0x679a:méi # 枚 0x679b:zhào # 枛 0x679c:guǒ # 果 0x679d:zhī,qí # 枝 0x679e:cōng,zōng # 枞 0x679f:yùn # 枟 0x67a1:shēng # 枡 0x67a2:shū # 枢 0x67a3:zǎo # 枣 0x67a5:lì # 枥 0x67a7:jiǎn # 枧 0x67a8:chéng # 枨 0x67aa:qiāng # 枪 0x67ab:fēng # 枫 0x67ac:zhān # 枬 0x67ad:xiāo # 枭 0x67ae:xiān,zhēn # 枮 0x67af:kū # 枯 0x67b0:píng # 枰 0x67b1:sì,tái # 枱 0x67b2:xǐ # 枲 0x67b3:zhǐ # 枳 0x67b4:guǎi # 枴 0x67b5:xiāo # 枵 0x67b6:jià # 架 0x67b7:jiā # 枷 0x67b8:jǔ,gǒu # 枸 0x67b9:bāo,fú # 枹 0x67ba:mò # 枺 0x67bb:yì,xiè # 枻 0x67bc:yè # 枼 0x67bd:yè # 枽 0x67be:shì # 枾 0x67bf:niè # 枿 0x67c0:bǐ # 柀 0x67c1:tuó,duò # 柁 0x67c2:yí,duò,lí # 柂 0x67c3:líng # 柃 0x67c4:bǐng # 柄 0x67c5:nǐ,chì # 柅 0x67c6:lā # 柆 0x67c7:hé # 柇 0x67c8:pán,bàn # 柈 0x67c9:fán # 柉 0x67ca:zhōng # 柊 0x67cb:dài # 柋 0x67cc:cí # 柌 0x67cd:yǎng,yàng,yāng,yīng # 柍 0x67ce:fū,fǔ,fù # 柎 0x67cf:bǎi,bó,bò # 柏 0x67d0:mǒu # 某 0x67d1:gān # 柑 0x67d2:qī # 柒 0x67d3:rǎn # 染 0x67d4:róu # 柔 0x67d5:mào # 柕 0x67d6:sháo,shào # 柖 0x67d7:sōng # 柗 0x67d8:zhè # 柘 0x67d9:xiá # 柙 0x67da:yòu,yóu # 柚 0x67db:shēn # 柛 0x67dc:guì,jǔ # 柜 0x67dd:tuò # 柝 0x67de:zuò,zhà # 柞 0x67df:nán # 柟 0x67e0:níng # 柠 0x67e1:yǒng # 柡 0x67e2:dǐ,chí # 柢 0x67e3:zhì,dié # 柣 0x67e4:zhā,zǔ,zū # 柤 0x67e5:chá,zhā # 查 0x67e6:dàn # 柦 0x67e7:gū # 柧 0x67e9:jiù # 柩 0x67ea:āo,ào # 柪 0x67eb:fú # 柫 0x67ec:jiǎn # 柬 0x67ed:bā,fú,pèi,bó,biē # 柭 0x67ee:duò,zuó,wù # 柮 0x67ef:kē # 柯 0x67f0:nài # 柰 0x67f1:zhù # 柱 0x67f2:bì,bié # 柲 0x67f3:liǔ # 柳 0x67f4:chái # 柴 0x67f5:shān # 柵 0x67f6:sì # 柶 0x67f7:zhù # 柷 0x67f8:bēi,pēi # 柸 0x67f9:shì,fèi # 柹 0x67fa:guǎi # 柺 0x67fb:chá,zhā # 査 0x67fc:yǎo # 柼 0x67fd:chēng # 柽 0x67fe:jiù # 柾 0x67ff:shì # 柿 0x6800:zhī # 栀 0x6801:liǔ # 栁 0x6802:méi # 栂 0x6804:róng # 栄 0x6805:zhà,shān,shi,cè # 栅 0x6807:biāo # 标 0x6808:zhàn # 栈 0x6809:zhì # 栉 0x680a:lóng # 栊 0x680b:dòng # 栋 0x680c:lú # 栌 0x680e:lì,yuè # 栎 0x680f:lán # 栏 0x6810:yǒng # 栐 0x6811:shù # 树 0x6812:xún # 栒 0x6813:shuān # 栓 0x6814:qì,qiè # 栔 0x6815:chén # 栕 0x6816:qī,xī # 栖 0x6817:lì # 栗 0x6818:yí # 栘 0x6819:xiáng # 栙 0x681a:zhèn # 栚 0x681b:lì # 栛 0x681c:sè # 栜 0x681d:guā,tiǎn,kuò # 栝 0x681e:kān # 栞 0x681f:bēn,bīng # 栟 0x6820:rěn # 栠 0x6821:xiào,jiào # 校 0x6822:bǎi # 栢 0x6823:rěn # 栣 0x6824:bìng # 栤 0x6825:zī # 栥 0x6826:chóu # 栦 0x6827:yì,xiè # 栧 0x6828:cì # 栨 0x6829:xǔ # 栩 0x682a:zhū # 株 0x682b:jiàn,zùn # 栫 0x682c:zuì # 栬 0x682d:ér # 栭 0x682e:ěr # 栮 0x682f:yǒu,yù # 栯 0x6830:fá # 栰 0x6831:gǒng # 栱 0x6832:kǎo # 栲 0x6833:lǎo # 栳 0x6834:zhān # 栴 0x6835:liè # 栵 0x6837:yàng # 样 0x6838:hé,hú # 核 0x6839:gēn # 根 0x683a:zhī,yì # 栺 0x683b:shì # 栻 0x683c:gé # 格 0x683d:zāi # 栽 0x683e:luán # 栾 0x683f:fú # 栿 0x6840:jié # 桀 0x6841:héng,háng # 桁 0x6842:guì # 桂 0x6843:táo # 桃 0x6844:guāng,guàng # 桄 0x6845:wéi # 桅 0x6846:kuàng # 框 0x6847:rú # 桇 0x6848:àn # 案 0x6849:ān # 桉 0x684a:juàn # 桊 0x684b:yí,tí # 桋 0x684c:zhuō # 桌 0x684d:kū # 桍 0x684e:zhì # 桎 0x684f:qióng # 桏 0x6850:tóng # 桐 0x6851:sāng # 桑 0x6852:sāng # 桒 0x6853:huán # 桓 0x6854:jié,jú # 桔 0x6855:jiù # 桕 0x6856:xuè # 桖 0x6857:duò # 桗 0x6858:chuí # 桘 0x6859:yú,móu # 桙 0x685a:zā,zǎn # 桚 0x685c:yīng # 桜 0x685f:zhàn # 桟 0x6860:yā # 桠 0x6861:ráo,náo # 桡 0x6862:zhēn # 桢 0x6863:dàng # 档 0x6864:qī # 桤 0x6865:qiáo # 桥 0x6866:huà # 桦 0x6867:guì,huì # 桧 0x6868:jiǎng # 桨 0x6869:zhuāng # 桩 0x686a:xún # 桪 0x686b:suō # 桫 0x686c:shā # 桬 0x686d:chén,zhèn # 桭 0x686e:bēi # 桮 0x686f:tīng,yíng # 桯 0x6870:guā # 桰 0x6871:jìng # 桱 0x6872:bó,po # 桲 0x6873:bèn,fàn # 桳 0x6874:fú # 桴 0x6875:ruí # 桵 0x6876:tǒng # 桶 0x6877:jué # 桷 0x6878:xī # 桸 0x6879:láng # 桹 0x687a:liǔ # 桺 0x687b:fēng,fèng # 桻 0x687c:qī # 桼 0x687d:wěn # 桽 0x687e:jūn # 桾 0x687f:gǎn # 桿 0x6880:sù,yìn # 梀 0x6881:liáng # 梁 0x6882:qiú # 梂 0x6883:tǐng,tìng # 梃 0x6884:yǒu # 梄 0x6885:méi # 梅 0x6886:bāng # 梆 0x6887:lòng # 梇 0x6888:pēng # 梈 0x6889:zhuāng # 梉 0x688a:dì # 梊 0x688b:xuān,juān,xié # 梋 0x688c:tú,chá # 梌 0x688d:zào # 梍 0x688e:āo,yòu # 梎 0x688f:gù # 梏 0x6890:bì # 梐 0x6891:dí # 梑 0x6892:hán # 梒 0x6893:zǐ # 梓 0x6894:zhī # 梔 0x6895:rèn,ér # 梕 0x6896:bèi # 梖 0x6897:gěng # 梗 0x6898:jiǎn # 梘 0x6899:huàn # 梙 0x689a:wǎn # 梚 0x689b:nuó # 梛 0x689c:jiā # 梜 0x689d:tiáo,tiāo # 條 0x689e:jì # 梞 0x689f:xiāo # 梟 0x68a0:lǚ # 梠 0x68a1:kuǎn # 梡 0x68a2:shāo,sào # 梢 0x68a3:chén,cén # 梣 0x68a4:fēn # 梤 0x68a5:sōng # 梥 0x68a6:mèng # 梦 0x68a7:wú # 梧 0x68a8:lí # 梨 0x68a9:sì,qǐ # 梩 0x68aa:dòu # 梪 0x68ab:qǐn # 梫 0x68ac:yǐng # 梬 0x68ad:suō # 梭 0x68ae:jū # 梮 0x68af:tī # 梯 0x68b0:xiè # 械 0x68b1:kǔn # 梱 0x68b2:zhuō # 梲 0x68b3:shū # 梳 0x68b4:chān,yán # 梴 0x68b5:fàn # 梵 0x68b6:wěi # 梶 0x68b7:jìng # 梷 0x68b8:lí # 梸 0x68b9:bīn,bīng # 梹 0x68bc:chóu,táo,dào # 梼 0x68bd:zhì # 梽 0x68be:lái # 梾 0x68bf:lián,liǎn # 梿 0x68c0:jiǎn # 检 0x68c1:zhuō # 棁 0x68c2:líng # 棂 0x68c3:lí # 棃 0x68c4:qì # 棄 0x68c5:bǐng # 棅 0x68c6:lún # 棆 0x68c7:cōng,sōng # 棇 0x68c8:qiàn # 棈 0x68c9:mián # 棉 0x68ca:qí # 棊 0x68cb:qí # 棋 0x68cc:cǎi # 棌 0x68cd:gùn,hùn # 棍 0x68ce:chán # 棎 0x68cf:dé,zhé # 棏 0x68d0:fěi # 棐 0x68d1:pái,bèi,pèi # 棑 0x68d2:bàng # 棒 0x68d3:bàng,pǒu,bèi,bēi # 棓 0x68d4:hūn # 棔 0x68d5:zōng # 棕 0x68d6:chéng # 棖 0x68d7:zǎo # 棗 0x68d8:jí # 棘 0x68d9:lì,liè # 棙 0x68da:péng # 棚 0x68db:yù # 棛 0x68dc:yù # 棜 0x68dd:gù # 棝 0x68de:jùn # 棞 0x68df:dòng # 棟 0x68e0:táng # 棠 0x68e1:gāng # 棡 0x68e2:wǎng # 棢 0x68e3:dì,dài,tì # 棣 0x68e4:què # 棤 0x68e5:fán # 棥 0x68e6:chēng # 棦 0x68e7:zhàn # 棧 0x68e8:qǐ # 棨 0x68e9:yuān # 棩 0x68ea:yǎn,yàn # 棪 0x68eb:yù # 棫 0x68ec:quān,juàn # 棬 0x68ed:yì # 棭 0x68ee:sēn # 森 0x68ef:rěn,shěn # 棯 0x68f0:chuí # 棰 0x68f1:léng,lēng,líng # 棱 0x68f2:qī # 棲 0x68f3:zhuō # 棳 0x68f4:fú,sù # 棴 0x68f5:kē # 棵 0x68f6:lái # 棶 0x68f7:zōu,sǒu # 棷 0x68f8:zōu # 棸 0x68f9:zhào,zhuō # 棹 0x68fa:guān # 棺 0x68fb:fēn # 棻 0x68fc:fén # 棼 0x68fd:chēn,shēn # 棽 0x68fe:qíng # 棾 0x68ff:ní,nǐ # 棿 0x6900:wǎn # 椀 0x6901:guǒ # 椁 0x6902:lù # 椂 0x6903:háo # 椃 0x6904:jiē,qiè # 椄 0x6905:yǐ,yī # 椅 0x6906:chóu,zhòu,diāo # 椆 0x6907:jǔ # 椇 0x6908:jú # 椈 0x6909:chéng,shèng # 椉 0x690a:zú,cuì # 椊 0x690b:liáng # 椋 0x690c:qiāng,kōng # 椌 0x690d:zhí # 植 0x690e:zhuī,chuí # 椎 0x690f:yā # 椏 0x6910:jū # 椐 0x6911:bēi,pí # 椑 0x6912:jiāo # 椒 0x6913:zhuó # 椓 0x6914:zī # 椔 0x6915:bīn # 椕 0x6916:péng # 椖 0x6917:dìng # 椗 0x6918:chǔ # 椘 0x691c:jiǎn # 検 0x691d:guī # 椝 0x691e:xì # 椞 0x691f:dú # 椟 0x6920:qiàn # 椠 0x6924:luó # 椤 0x6925:zhī # 椥 0x692a:pèng # 椪 0x692b:shàn # 椫 0x692d:tuǒ # 椭 0x692e:sēn # 椮 0x692f:duǒ,chuán # 椯 0x6930:yē # 椰 0x6931:fù # 椱 0x6932:wěi,huī # 椲 0x6933:wēi # 椳 0x6934:duàn # 椴 0x6935:jiǎ,jiā # 椵 0x6936:zōng # 椶 0x6937:jiān,hán # 椷 0x6938:yí # 椸 0x6939:zhēn,shèn # 椹 0x693a:xí # 椺 0x693b:yàn,yà # 椻 0x693c:yǎn # 椼 0x693d:chuán # 椽 0x693e:jiān # 椾 0x693f:chūn # 椿 0x6940:yǔ # 楀 0x6941:hé # 楁 0x6942:zhā,chá # 楂 0x6943:wò # 楃 0x6944:piān # 楄 0x6945:bī # 楅 0x6946:yāo # 楆 0x6947:guō,kuǎ # 楇 0x6948:xū # 楈 0x6949:ruò # 楉 0x694a:yáng # 楊 0x694b:là # 楋 0x694c:yán # 楌 0x694d:běn # 楍 0x694e:huī # 楎 0x694f:kuí # 楏 0x6950:jiè # 楐 0x6951:kuí # 楑 0x6952:sī # 楒 0x6953:fēng # 楓 0x6954:xiē # 楔 0x6955:tuǒ # 楕 0x6956:jí,zhì # 楖 0x6957:jiàn # 楗 0x6958:mù # 楘 0x6959:máo # 楙 0x695a:chǔ # 楚 0x695b:kǔ,hù # 楛 0x695c:hú # 楜 0x695d:liàn # 楝 0x695e:léng # 楞 0x695f:tíng # 楟 0x6960:nán # 楠 0x6961:yú # 楡 0x6962:yóu,yǒu # 楢 0x6963:méi # 楣 0x6964:sǒng,cōng # 楤 0x6965:xuàn,yuán # 楥 0x6966:xuàn # 楦 0x6967:yǎng,yàng,yīng # 楧 0x6968:zhēn # 楨 0x6969:pián # 楩 0x696a:dié,yè # 楪 0x696b:jí # 楫 0x696c:jiē # 楬 0x696d:yè # 業 0x696e:chǔ # 楮 0x696f:shǔn,dùn # 楯 0x6970:yú # 楰 0x6971:còu,zòu # 楱 0x6972:wēi # 楲 0x6973:méi # 楳 0x6974:dì,dǐ,shì # 楴 0x6975:jí # 極 0x6976:jié # 楶 0x6977:kǎi,jiē # 楷 0x6978:qiū # 楸 0x6979:yíng # 楹 0x697a:róu,ròu # 楺 0x697b:huáng # 楻 0x697c:lóu # 楼 0x697d:lè,yuè # 楽 0x6980:pǐn # 榀 0x6982:gài # 概 0x6983:tán # 榃 0x6984:lǎn # 榄 0x6985:wēn,yùn # 榅 0x6986:yú # 榆 0x6987:chèn # 榇 0x6988:lǘ # 榈 0x6989:jǔ # 榉 0x698d:xiè # 榍 0x698e:jiǎ # 榎 0x698f:yì # 榏 0x6990:zhǎn,niǎn,zhèn # 榐 0x6991:fú,fù,bó # 榑 0x6992:nuò # 榒 0x6993:mì # 榓 0x6994:láng # 榔 0x6995:róng # 榕 0x6996:gǔ # 榖 0x6997:jiàn,jìn # 榗 0x6998:jǔ # 榘 0x6999:tā # 榙 0x699a:yǎo # 榚 0x699b:zhēn # 榛 0x699c:bǎng,bàng # 榜 0x699d:shā,xiè # 榝 0x699e:yuán # 榞 0x699f:zǐ # 榟 0x69a0:míng # 榠 0x69a1:sù # 榡 0x69a2:jià # 榢 0x69a3:yáo # 榣 0x69a4:jié # 榤 0x69a5:huàng # 榥 0x69a6:gàn # 榦 0x69a7:fěi # 榧 0x69a8:zhà # 榨 0x69a9:qián # 榩 0x69aa:mà,mā # 榪 0x69ab:sǔn # 榫 0x69ac:yuán # 榬 0x69ad:xiè # 榭 0x69ae:róng # 榮 0x69af:shí # 榯 0x69b0:zhī # 榰 0x69b1:cuī # 榱 0x69b2:wēn # 榲 0x69b3:tíng # 榳 0x69b4:liú # 榴 0x69b5:róng # 榵 0x69b6:táng # 榶 0x69b7:què # 榷 0x69b8:zhāi # 榸 0x69b9:sì # 榹 0x69ba:shèng # 榺 0x69bb:tà # 榻 0x69bc:kē # 榼 0x69bd:xī # 榽 0x69be:gù # 榾 0x69bf:qī # 榿 0x69c0:gǎo # 槀 0x69c1:gǎo # 槁 0x69c2:sūn # 槂 0x69c3:pán # 槃 0x69c4:tāo # 槄 0x69c5:gé # 槅 0x69c6:chūn # 槆 0x69c7:diān # 槇 0x69c8:nòu # 槈 0x69c9:jí # 槉 0x69ca:shuò # 槊 0x69cb:gòu # 構 0x69cc:chuí # 槌 0x69cd:qiāng # 槍 0x69ce:chá # 槎 0x69cf:qiǎn,lián,xiàn # 槏 0x69d0:huái # 槐 0x69d1:méi # 槑 0x69d2:xù # 槒 0x69d3:gàng # 槓 0x69d4:gāo # 槔 0x69d5:zhuō # 槕 0x69d6:tuó # 槖 0x69d8:yàng # 様 0x69d9:diān,zhěn,zhēn # 槙 0x69da:jiǎ # 槚 0x69db:jiàn,kǎn # 槛 0x69dc:zuì # 槜 0x69df:bīn,bīng # 槟 0x69e0:zhū # 槠 0x69e2:xí,dié # 槢 0x69e3:jī,guī # 槣 0x69e4:lián,liǎn # 槤 0x69e5:huì # 槥 0x69e6:róng,yōng # 槦 0x69e7:qiàn # 槧 0x69e8:guǒ # 槨 0x69e9:gài # 槩 0x69ea:gài # 槪 0x69eb:tuán,shuàn,quán # 槫 0x69ec:huà # 槬 0x69ed:qì,sè # 槭 0x69ee:sēn # 槮 0x69ef:cuī,zhǐ # 槯 0x69f0:pèng # 槰 0x69f1:yǒu,chǎo # 槱 0x69f2:hú # 槲 0x69f3:jiǎng # 槳 0x69f4:hù # 槴 0x69f5:huàn # 槵 0x69f6:guì # 槶 0x69f7:niè # 槷 0x69f8:yì # 槸 0x69f9:gāo # 槹 0x69fa:kāng # 槺 0x69fb:guī # 槻 0x69fc:guī # 槼 0x69fd:cáo # 槽 0x69fe:màn,wàn # 槾 0x69ff:jǐn # 槿 0x6a00:dī # 樀 0x6a01:zhuāng # 樁 0x6a02:lè,yuè,yào,lào # 樂 0x6a03:láng # 樃 0x6a04:chén # 樄 0x6a05:cōng,zōng # 樅 0x6a06:lí,chī # 樆 0x6a07:xiū # 樇 0x6a08:qíng # 樈 0x6a09:shǎng,shuǎng # 樉 0x6a0a:fán # 樊 0x6a0b:tōng # 樋 0x6a0c:guàn # 樌 0x6a0d:zé # 樍 0x6a0e:sù # 樎 0x6a0f:léi,lěi # 樏 0x6a10:lǔ # 樐 0x6a11:liáng # 樑 0x6a12:mì # 樒 0x6a13:lóu # 樓 0x6a14:cháo,jiǎo,chāo # 樔 0x6a15:sù # 樕 0x6a16:kē # 樖 0x6a17:chū # 樗 0x6a18:táng # 樘 0x6a19:biāo # 標 0x6a1a:lù # 樚 0x6a1b:jiū,liáo # 樛 0x6a1c:zhè # 樜 0x6a1d:zhā # 樝 0x6a1e:shū # 樞 0x6a1f:zhāng # 樟 0x6a20:mán # 樠 0x6a21:mó,mú # 模 0x6a22:niǎo,mù # 樢 0x6a23:yàng # 樣 0x6a24:tiáo # 樤 0x6a25:péng # 樥 0x6a26:zhù # 樦 0x6a27:shā,xiè # 樧 0x6a28:xī # 樨 0x6a29:quán # 権 0x6a2a:héng,hèng # 横 0x6a2b:jiān # 樫 0x6a2c:cōng # 樬 0x6a2f:qiáng # 樯 0x6a31:yīng # 樱 0x6a32:èr # 樲 0x6a33:xún # 樳 0x6a34:zhí # 樴 0x6a35:qiáo # 樵 0x6a36:zuī # 樶 0x6a37:cóng # 樷 0x6a38:pǔ # 樸 0x6a39:shù # 樹 0x6a3a:huà # 樺 0x6a3b:guì # 樻 0x6a3c:zhēn # 樼 0x6a3d:zūn # 樽 0x6a3e:yuè # 樾 0x6a3f:shàn # 樿 0x6a40:xī # 橀 0x6a41:chūn # 橁 0x6a42:diàn # 橂 0x6a43:fá,fèi # 橃 0x6a44:gǎn # 橄 0x6a45:mó # 橅 0x6a46:wú # 橆 0x6a47:qiāo # 橇 0x6a48:ráo,náo # 橈 0x6a49:lìn # 橉 0x6a4a:liú # 橊 0x6a4b:qiáo # 橋 0x6a4c:xiàn # 橌 0x6a4d:rùn # 橍 0x6a4e:fǎn # 橎 0x6a4f:zhǎn,jiǎn # 橏 0x6a50:tuó # 橐 0x6a51:liáo # 橑 0x6a52:yún # 橒 0x6a53:shùn # 橓 0x6a54:tuí,dūn # 橔 0x6a55:chēng # 橕 0x6a56:táng,chēng # 橖 0x6a57:méng # 橗 0x6a58:jú # 橘 0x6a59:chéng # 橙 0x6a5a:sù,qiū # 橚 0x6a5b:jué # 橛 0x6a5c:jué # 橜 0x6a5d:tán,diàn # 橝 0x6a5e:huì # 橞 0x6a5f:jī # 機 0x6a60:nuó # 橠 0x6a61:xiàng # 橡 0x6a62:tuǒ # 橢 0x6a63:níng # 橣 0x6a64:ruǐ # 橤 0x6a65:zhū # 橥 0x6a66:tóng,chuáng # 橦 0x6a67:zēng,céng # 橧 0x6a68:fén,fèn,fèi # 橨 0x6a69:qióng # 橩 0x6a6a:rǎn,yān # 橪 0x6a6b:héng,hèng # 橫 0x6a6c:qián # 橬 0x6a6d:gū # 橭 0x6a6e:liǔ # 橮 0x6a6f:lào # 橯 0x6a70:gāo # 橰 0x6a71:chú # 橱 0x6a76:jǐ # 橶 0x6a77:dōu # 橷 0x6a79:lǔ # 橹 0x6a7c:yuán # 橼 0x6a7d:tà # 橽 0x6a7e:shū,qiāo # 橾 0x6a7f:jiāng # 橿 0x6a80:tán # 檀 0x6a81:lǐn # 檁 0x6a82:nóng # 檂 0x6a83:yǐn # 檃 0x6a84:xí # 檄 0x6a85:huì # 檅 0x6a86:shān # 檆 0x6a87:zuì # 檇 0x6a88:xuán # 檈 0x6a89:chēng # 檉 0x6a8a:gàn # 檊 0x6a8b:jū # 檋 0x6a8c:zuì # 檌 0x6a8d:yì # 檍 0x6a8e:qín # 檎 0x6a8f:pǔ # 檏 0x6a90:yán # 檐 0x6a91:léi # 檑 0x6a92:fēng # 檒 0x6a93:huǐ # 檓 0x6a94:dàng # 檔 0x6a95:jì # 檕 0x6a96:suì # 檖 0x6a97:bò # 檗 0x6a98:píng,bò # 檘 0x6a99:chéng # 檙 0x6a9a:chǔ # 檚 0x6a9b:zhuā # 檛 0x6a9c:guì,huì # 檜 0x6a9d:jí # 檝 0x6a9e:jiě # 檞 0x6a9f:jiǎ # 檟 0x6aa0:qíng # 檠 0x6aa1:zhái,shì,tú # 檡 0x6aa2:jiǎn # 檢 0x6aa3:qiáng # 檣 0x6aa4:dào # 檤 0x6aa5:yǐ # 檥 0x6aa6:biāo,biǎo # 檦 0x6aa7:sōng # 檧 0x6aa8:shē # 檨 0x6aa9:lǐn # 檩 0x6aab:chá # 檫 0x6aac:méng # 檬 0x6aad:yín # 檭 0x6aae:chóu,táo,dǎo # 檮 0x6aaf:tái # 檯 0x6ab0:mián # 檰 0x6ab1:qí # 檱 0x6ab3:bīn,bīng # 檳 0x6ab4:huò # 檴 0x6ab5:jì # 檵 0x6ab6:qiān,lián # 檶 0x6ab7:nǐ,mí # 檷 0x6ab8:níng # 檸 0x6ab9:yī # 檹 0x6aba:gǎo # 檺 0x6abb:jiàn,kǎn # 檻 0x6abc:yǐn # 檼 0x6abd:nòu,ruǎn,rú # 檽 0x6abe:qǐng # 檾 0x6abf:yǎn # 檿 0x6ac0:qí # 櫀 0x6ac1:mì # 櫁 0x6ac2:zhào # 櫂 0x6ac3:guì # 櫃 0x6ac4:chūn # 櫄 0x6ac5:jī,jì # 櫅 0x6ac6:kuí # 櫆 0x6ac7:pó # 櫇 0x6ac8:dèng # 櫈 0x6ac9:chú # 櫉 0x6acb:mián # 櫋 0x6acc:yōu # 櫌 0x6acd:zhì # 櫍 0x6ace:huǎng,guǒ,gǔ # 櫎 0x6acf:qiān # 櫏 0x6ad0:lěi # 櫐 0x6ad1:léi,lěi # 櫑 0x6ad2:sà # 櫒 0x6ad3:lǔ # 櫓 0x6ad4:lì # 櫔 0x6ad5:cuán # 櫕 0x6ad6:lǜ,chū # 櫖 0x6ad7:miè,mèi # 櫗 0x6ad8:huì # 櫘 0x6ad9:ōu # 櫙 0x6ada:lǘ # 櫚 0x6adb:zhì # 櫛 0x6adc:gāo # 櫜 0x6add:dú # 櫝 0x6ade:yuán # 櫞 0x6adf:lì,yuè # 櫟 0x6ae0:fèi # 櫠 0x6ae1:zhuó,zhù # 櫡 0x6ae2:sǒu # 櫢 0x6ae3:lián,liǎn # 櫣 0x6ae5:chú # 櫥 0x6ae7:zhū # 櫧 0x6ae8:lú # 櫨 0x6ae9:yán # 櫩 0x6aea:lì # 櫪 0x6aeb:zhū # 櫫 0x6aec:chèn # 櫬 0x6aed:jué,jì # 櫭 0x6aee:è # 櫮 0x6aef:sū # 櫯 0x6af0:huái,guī # 櫰 0x6af1:niè # 櫱 0x6af2:yù # 櫲 0x6af3:lóng # 櫳 0x6af4:là,lài # 櫴 0x6af6:xiǎn # 櫶 0x6af8:jǔ # 櫸 0x6af9:xiāo # 櫹 0x6afa:líng # 櫺 0x6afb:yīng # 櫻 0x6afc:jiān # 櫼 0x6afd:yǐn # 櫽 0x6afe:yòu,yóu # 櫾 0x6aff:yíng # 櫿 0x6b00:xiāng # 欀 0x6b01:nóng # 欁 0x6b02:bó # 欂 0x6b03:chán,zhàn # 欃 0x6b04:lán # 欄 0x6b05:jǔ # 欅 0x6b06:shuāng # 欆 0x6b07:shè # 欇 0x6b08:wéi,zuì # 欈 0x6b09:cóng # 欉 0x6b0a:quán # 權 0x6b0b:qú # 欋 0x6b0e:yù # 欎 0x6b0f:luó # 欏 0x6b10:lì # 欐 0x6b11:cuán # 欑 0x6b12:luán # 欒 0x6b13:dǎng # 欓 0x6b14:qú # 欔 0x6b16:lǎn # 欖 0x6b17:lán # 欗 0x6b18:zhú # 欘 0x6b19:léi # 欙 0x6b1a:lǐ # 欚 0x6b1b:bà # 欛 0x6b1c:náng # 欜 0x6b1d:yù # 欝 0x6b1e:líng # 欞 0x6b20:qiàn # 欠 0x6b21:cì # 次 0x6b22:huān # 欢 0x6b23:xīn # 欣 0x6b24:yú # 欤 0x6b25:yù,yì # 欥 0x6b26:qiān,xiān # 欦 0x6b27:ōu # 欧 0x6b28:xū # 欨 0x6b29:chāo # 欩 0x6b2a:chù,qù,xì # 欪 0x6b2b:qì # 欫 0x6b2c:kài,ài # 欬 0x6b2d:yì,yīn # 欭 0x6b2e:jué # 欮 0x6b2f:xì,kài # 欯 0x6b30:xù # 欰 0x6b31:hē # 欱 0x6b32:yù # 欲 0x6b33:kuài # 欳 0x6b34:láng # 欴 0x6b35:kuǎn # 欵 0x6b36:shuò,sòu # 欶 0x6b37:xī # 欷 0x6b38:ēi,éi,ěi,èi,ǎi # 欸 0x6b39:qī # 欹 0x6b3a:qī # 欺 0x6b3b:xū,chuā # 欻 0x6b3c:chǐ,chuài # 欼 0x6b3d:qīn # 欽 0x6b3e:kuǎn # 款 0x6b3f:kǎn,qiàn # 欿 0x6b40:kuǎn # 歀 0x6b41:kǎn,kè # 歁 0x6b42:chuǎn,chuán # 歂 0x6b43:shà # 歃 0x6b45:yān,yīn # 歅 0x6b46:xīn # 歆 0x6b47:xiē # 歇 0x6b48:yú # 歈 0x6b49:qiàn # 歉 0x6b4a:xiāo # 歊 0x6b4b:yē # 歋 0x6b4c:gē # 歌 0x6b4d:wū # 歍 0x6b4e:tàn # 歎 0x6b4f:jìn,qūn # 歏 0x6b50:ōu # 歐 0x6b51:hū # 歑 0x6b52:tì # 歒 0x6b53:huān # 歓 0x6b54:xū # 歔 0x6b55:pēn # 歕 0x6b56:xǐ # 歖 0x6b57:xiào # 歗 0x6b58:xū # 歘 0x6b59:xī,shè # 歙 0x6b5b:liǎn,hān # 歛 0x6b5c:chù # 歜 0x6b5d:yì # 歝 0x6b5e:è # 歞 0x6b5f:yú # 歟 0x6b60:chuò # 歠 0x6b61:huān # 歡 0x6b62:zhǐ # 止 0x6b63:zhèng,zhēng # 正 0x6b64:cǐ # 此 0x6b65:bù # 步 0x6b66:wǔ # 武 0x6b67:qí # 歧 0x6b68:bù # 歨 0x6b69:bù # 歩 0x6b6a:wāi # 歪 0x6b6b:jù # 歫 0x6b6c:qián # 歬 0x6b6d:zhì,chí # 歭 0x6b6e:sè # 歮 0x6b6f:chǐ # 歯 0x6b70:sè,shà # 歰 0x6b71:zhǒng # 歱 0x6b72:suì # 歲 0x6b73:suì # 歳 0x6b74:lì # 歴 0x6b75:zé # 歵 0x6b76:yú # 歶 0x6b77:lì # 歷 0x6b78:guī # 歸 0x6b79:dǎi # 歹 0x6b7a:è # 歺 0x6b7b:sǐ # 死 0x6b7c:jiān # 歼 0x6b7d:zhé # 歽 0x6b7e:mò,wěn # 歾 0x6b7f:mò # 歿 0x6b80:yāo # 殀 0x6b81:mò # 殁 0x6b82:cú # 殂 0x6b83:yāng # 殃 0x6b84:tiǎn # 殄 0x6b85:shēng # 殅 0x6b86:dài # 殆 0x6b87:shāng # 殇 0x6b88:xù # 殈 0x6b89:xùn # 殉 0x6b8a:shū # 殊 0x6b8b:cán # 残 0x6b8c:jǐng,jué # 殌 0x6b8d:piǎo # 殍 0x6b8e:qià # 殎 0x6b8f:qiú # 殏 0x6b90:sù # 殐 0x6b91:qíng,jìng # 殑 0x6b92:yǔn # 殒 0x6b93:liàn # 殓 0x6b94:yì # 殔 0x6b95:fǒu,bó # 殕 0x6b96:zhí,shi # 殖 0x6b97:yè,yān,yàn # 殗 0x6b98:cán # 殘 0x6b99:hūn,mèi # 殙 0x6b9a:dān # 殚 0x6b9b:jí # 殛 0x6b9c:dié # 殜 0x6b9e:yǔn # 殞 0x6b9f:wēn # 殟 0x6ba0:chòu # 殠 0x6ba1:bìn # 殡 0x6ba2:tì # 殢 0x6ba3:jìn # 殣 0x6ba4:shāng # 殤 0x6ba5:yín # 殥 0x6ba6:chī # 殦 0x6ba7:jiù # 殧 0x6ba8:kuì,huì # 殨 0x6ba9:cuàn # 殩 0x6baa:yì # 殪 0x6bab:dān # 殫 0x6bac:dù # 殬 0x6bad:jiāng # 殭 0x6bae:liàn # 殮 0x6baf:bìn # 殯 0x6bb0:dú # 殰 0x6bb2:jiān # 殲 0x6bb3:shū # 殳 0x6bb4:ōu # 殴 0x6bb5:duàn # 段 0x6bb6:zhù # 殶 0x6bb7:yīn,yān,yǐn # 殷 0x6bb8:qìng,kēng,shēng # 殸 0x6bb9:yì # 殹 0x6bba:shā # 殺 0x6bbb:ké,qiào # 殻 0x6bbc:ké,qiào # 殼 0x6bbd:xiáo,yáo,xiào # 殽 0x6bbe:xùn # 殾 0x6bbf:diàn # 殿 0x6bc0:huǐ # 毀 0x6bc1:huǐ # 毁 0x6bc2:gǔ # 毂 0x6bc3:qiāo # 毃 0x6bc4:jī # 毄 0x6bc5:yì # 毅 0x6bc6:ōu # 毆 0x6bc7:huǐ # 毇 0x6bc8:duàn # 毈 0x6bc9:yī # 毉 0x6bca:xiāo # 毊 0x6bcb:wú # 毋 0x6bcc:guàn,wān # 毌 0x6bcd:mǔ # 母 0x6bce:měi # 毎 0x6bcf:měi # 每 0x6bd0:ǎi # 毐 0x6bd1:jiě # 毑 0x6bd2:dú,dài # 毒 0x6bd3:yù # 毓 0x6bd4:bǐ # 比 0x6bd5:bì # 毕 0x6bd6:bì # 毖 0x6bd7:pí # 毗 0x6bd8:pí # 毘 0x6bd9:bì # 毙 0x6bda:chán # 毚 0x6bdb:máo # 毛 0x6bde:bǐ # 毞 0x6be0:jiā # 毠 0x6be1:zhān # 毡 0x6be2:sāi # 毢 0x6be3:mù # 毣 0x6be4:tuò # 毤 0x6be5:xún,xùn # 毥 0x6be6:ěr # 毦 0x6be7:róng # 毧 0x6be8:xiǎn # 毨 0x6be9:jū # 毩 0x6bea:mú # 毪 0x6beb:háo # 毫 0x6bec:qiú # 毬 0x6bed:dòu,nuò # 毭 0x6bef:tǎn # 毯 0x6bf0:péi # 毰 0x6bf1:jū # 毱 0x6bf2:duō # 毲 0x6bf3:cuì # 毳 0x6bf4:bī # 毴 0x6bf5:sān # 毵 0x6bf7:mào # 毷 0x6bf8:sāi,suī # 毸 0x6bf9:shū # 毹 0x6bfa:shū # 毺 0x6bfb:tuò # 毻 0x6bfc:hé # 毼 0x6bfd:jiàn # 毽 0x6bfe:tà # 毾 0x6bff:sān # 毿 0x6c00:lǘ # 氀 0x6c01:mú # 氁 0x6c02:máo # 氂 0x6c03:tóng # 氃 0x6c04:rǒng # 氄 0x6c05:chǎng # 氅 0x6c06:pǔ # 氆 0x6c07:lǔ # 氇 0x6c08:zhān # 氈 0x6c09:sào # 氉 0x6c0a:zhān # 氊 0x6c0b:méng # 氋 0x6c0c:lǔ # 氌 0x6c0d:qú # 氍 0x6c0e:dié # 氎 0x6c0f:shì,zhī # 氏 0x6c10:dī,dǐ # 氐 0x6c11:mín # 民 0x6c12:jué # 氒 0x6c13:méng,máng # 氓 0x6c14:qì # 气 0x6c15:piē # 氕 0x6c16:nǎi # 氖 0x6c17:qì # 気 0x6c18:dāo # 氘 0x6c19:xiān # 氙 0x6c1a:chuān # 氚 0x6c1b:fēn # 氛 0x6c1c:yáng,rì # 氜 0x6c1d:nèi # 氝 0x6c1f:fú # 氟 0x6c20:shēn # 氠 0x6c21:dōng # 氡 0x6c22:qīng # 氢 0x6c23:qì # 氣 0x6c24:yīn # 氤 0x6c25:xī # 氥 0x6c26:hài # 氦 0x6c27:yǎng # 氧 0x6c28:ān # 氨 0x6c29:yà # 氩 0x6c2a:kè # 氪 0x6c2b:qīng # 氫 0x6c2c:yà # 氬 0x6c2d:dōng # 氭 0x6c2e:dàn # 氮 0x6c2f:lǜ # 氯 0x6c30:qíng # 氰 0x6c31:yǎng # 氱 0x6c32:yūn # 氲 0x6c33:yūn # 氳 0x6c34:shuǐ # 水 0x6c36:zhěng,chéng,zhèng # 氶 0x6c37:bīng # 氷 0x6c38:yǒng # 永 0x6c39:dàng # 氹 0x6c3b:lè # 氻 0x6c3c:nì # 氼 0x6c3d:tǔn # 氽 0x6c3e:fàn # 氾 0x6c3f:guǐ,jiǔ # 氿 0x6c40:tīng # 汀 0x6c41:zhī # 汁 0x6c42:qiú # 求 0x6c43:bīn,pà,pā # 汃 0x6c44:zè # 汄 0x6c45:miǎn # 汅 0x6c46:cuān # 汆 0x6c47:huì # 汇 0x6c48:diāo # 汈 0x6c49:hàn # 汉 0x6c4a:chà # 汊 0x6c4b:zhuó,què # 汋 0x6c4c:chuàn # 汌 0x6c4d:wán # 汍 0x6c4e:fàn # 汎 0x6c4f:tài,dà # 汏 0x6c50:xī # 汐 0x6c51:tuō # 汑 0x6c52:máng # 汒 0x6c53:qiú # 汓 0x6c54:qì # 汔 0x6c55:shàn # 汕 0x6c56:pìn # 汖 0x6c57:hàn,hán # 汗 0x6c58:qiān # 汘 0x6c59:wū # 汙 0x6c5a:wū # 汚 0x6c5b:xùn # 汛 0x6c5c:sì # 汜 0x6c5d:rǔ # 汝 0x6c5e:gǒng # 汞 0x6c5f:jiāng # 江 0x6c60:chí # 池 0x6c61:wū # 污 0x6c64:tāng,shāng # 汤 0x6c65:zhī,jì # 汥 0x6c66:zhǐ # 汦 0x6c67:qiān # 汧 0x6c68:mì # 汨 0x6c69:gǔ,yù # 汩 0x6c6a:wāng # 汪 0x6c6b:jǐng # 汫 0x6c6c:jǐng # 汬 0x6c6d:ruì # 汭 0x6c6e:jūn # 汮 0x6c6f:hóng # 汯 0x6c70:tài # 汰 0x6c71:tài # 汱 0x6c72:jí # 汲 0x6c73:biàn # 汳 0x6c74:biàn # 汴 0x6c75:gàn,hán,cén # 汵 0x6c76:wèn,mén # 汶 0x6c77:zhōng # 汷 0x6c78:fāng,pāng # 汸 0x6c79:xiōng # 汹 0x6c7a:jué # 決 0x6c7b:hǔ,huǎng # 汻 0x6c7d:qì # 汽 0x6c7e:fén # 汾 0x6c7f:xù # 汿 0x6c80:xù # 沀 0x6c81:qìn # 沁 0x6c82:yí # 沂 0x6c83:wò # 沃 0x6c84:yún # 沄 0x6c85:yuán # 沅 0x6c86:hàng # 沆 0x6c87:yǎn # 沇 0x6c88:shěn,chén # 沈 0x6c89:chén # 沉 0x6c8a:dàn # 沊 0x6c8b:yóu # 沋 0x6c8c:dùn,zhuàn # 沌 0x6c8d:hù # 沍 0x6c8e:huò # 沎 0x6c8f:qī # 沏 0x6c90:mù # 沐 0x6c91:nǜ,niǔ # 沑 0x6c92:méi,mò # 沒 0x6c93:tà,dá # 沓 0x6c94:miǎn # 沔 0x6c95:mì,wù # 沕 0x6c96:chōng # 沖 0x6c97:hóng,pāng # 沗 0x6c98:bǐ # 沘 0x6c99:shā,shà # 沙 0x6c9a:zhǐ # 沚 0x6c9b:pèi # 沛 0x6c9c:pàn # 沜 0x6c9d:zhuǐ,zǐ # 沝 0x6c9e:zā # 沞 0x6c9f:gōu # 沟 0x6ca0:pài # 沠 0x6ca1:méi,mò # 没 0x6ca2:zé # 沢 0x6ca3:fēng # 沣 0x6ca4:òu,ōu # 沤 0x6ca5:lì # 沥 0x6ca6:lún # 沦 0x6ca7:cāng # 沧 0x6ca8:fēng # 沨 0x6ca9:wéi # 沩 0x6caa:hù # 沪 0x6cab:mò # 沫 0x6cac:mèi # 沬 0x6cad:shù # 沭 0x6cae:jǔ,jù # 沮 0x6caf:zá # 沯 0x6cb0:tuō,duó # 沰 0x6cb1:tuó # 沱 0x6cb2:tuó,duò # 沲 0x6cb3:hé # 河 0x6cb4:lì # 沴 0x6cb5:mǐ,lì # 沵 0x6cb6:yí,chí # 沶 0x6cb7:fā # 沷 0x6cb8:fèi # 沸 0x6cb9:yóu # 油 0x6cba:tián # 沺 0x6cbb:zhì # 治 0x6cbc:zhǎo # 沼 0x6cbd:gū # 沽 0x6cbe:zhān # 沾 0x6cbf:yán # 沿 0x6cc0:sī # 泀 0x6cc1:kuàng # 況 0x6cc2:jiǒng # 泂 0x6cc3:jū # 泃 0x6cc4:xiè,yì # 泄 0x6cc5:qiú # 泅 0x6cc6:yì,dié # 泆 0x6cc7:jiā # 泇 0x6cc8:zhōng # 泈 0x6cc9:quán # 泉 0x6cca:bó,pō # 泊 0x6ccb:huì # 泋 0x6ccc:mì,bì # 泌 0x6ccd:bēn,bèn # 泍 0x6cce:zé # 泎 0x6ccf:chù,shè # 泏 0x6cd0:lè # 泐 0x6cd1:yōu,yòu,āo # 泑 0x6cd2:gū # 泒 0x6cd3:hóng # 泓 0x6cd4:gān # 泔 0x6cd5:fǎ # 法 0x6cd6:mǎo # 泖 0x6cd7:sì # 泗 0x6cd8:hū # 泘 0x6cd9:pēng,píng # 泙 0x6cda:cǐ # 泚 0x6cdb:fàn # 泛 0x6cdc:zhī # 泜 0x6cdd:sù # 泝 0x6cde:nìng # 泞 0x6cdf:chēng # 泟 0x6ce0:líng # 泠 0x6ce1:pào,pāo # 泡 0x6ce2:bō # 波 0x6ce3:qì # 泣 0x6ce4:sì # 泤 0x6ce5:ní,nì # 泥 0x6ce6:jú # 泦 0x6ce7:yuè,sà # 泧 0x6ce8:zhù # 注 0x6ce9:shēng # 泩 0x6cea:lèi # 泪 0x6ceb:xuàn # 泫 0x6cec:jué,xuè # 泬 0x6ced:fú # 泭 0x6cee:pàn # 泮 0x6cef:mǐn # 泯 0x6cf0:tài # 泰 0x6cf1:yāng # 泱 0x6cf2:jǐ # 泲 0x6cf3:yǒng # 泳 0x6cf4:guàn # 泴 0x6cf5:bèng # 泵 0x6cf6:xué # 泶 0x6cf7:lóng,shuāng # 泷 0x6cf8:lú # 泸 0x6cfa:luò,pō # 泺 0x6cfb:xiè # 泻 0x6cfc:pō # 泼 0x6cfd:zé,shì # 泽 0x6cfe:jīng # 泾 0x6cff:yín # 泿 0x6d00:pán # 洀 0x6d01:jié # 洁 0x6d02:yè # 洂 0x6d03:huī # 洃 0x6d04:huí # 洄 0x6d05:zài # 洅 0x6d06:chéng # 洆 0x6d07:yīn # 洇 0x6d08:wéi # 洈 0x6d09:hòu # 洉 0x6d0a:jiàn # 洊 0x6d0b:yáng # 洋 0x6d0c:liè # 洌 0x6d0d:sì # 洍 0x6d0e:jì # 洎 0x6d0f:ér # 洏 0x6d10:xíng # 洐 0x6d11:fú,fù # 洑 0x6d12:sǎ,xǐ # 洒 0x6d13:sè,qì,zì # 洓 0x6d14:zhǐ # 洔 0x6d15:yìn # 洕 0x6d16:wú # 洖 0x6d17:xǐ,xiǎn # 洗 0x6d18:kǎo,kào # 洘 0x6d19:zhū # 洙 0x6d1a:jiàng # 洚 0x6d1b:luò # 洛 0x6d1d:àn,yàn,è # 洝 0x6d1e:dòng # 洞 0x6d1f:yí # 洟 0x6d20:sì # 洠 0x6d21:lěi,lèi # 洡 0x6d22:yī # 洢 0x6d23:mǐ # 洣 0x6d24:quán # 洤 0x6d25:jīn # 津 0x6d26:pò # 洦 0x6d27:wěi # 洧 0x6d28:xiáo # 洨 0x6d29:xiè # 洩 0x6d2a:hóng # 洪 0x6d2b:xù # 洫 0x6d2c:sù,shuò # 洬 0x6d2d:kuāng # 洭 0x6d2e:táo # 洮 0x6d2f:qiè,jié # 洯 0x6d30:jù # 洰 0x6d31:ěr # 洱 0x6d32:zhōu # 洲 0x6d33:rù # 洳 0x6d34:píng # 洴 0x6d35:xún # 洵 0x6d36:xiōng # 洶 0x6d37:zhì # 洷 0x6d38:guāng # 洸 0x6d39:huán # 洹 0x6d3a:míng # 洺 0x6d3b:huó # 活 0x6d3c:wā # 洼 0x6d3d:qià # 洽 0x6d3e:pài,pā # 派 0x6d3f:wū # 洿 0x6d40:qū # 浀 0x6d41:liú # 流 0x6d42:yì # 浂 0x6d43:jiā # 浃 0x6d44:jìng # 浄 0x6d45:qiǎn,jiān # 浅 0x6d46:jiāng,jiàng # 浆 0x6d47:jiāo # 浇 0x6d48:zhēn # 浈 0x6d49:shī # 浉 0x6d4a:zhuó # 浊 0x6d4b:cè # 测 0x6d4d:kuài,huì # 浍 0x6d4e:jì,jǐ # 济 0x6d4f:liú # 浏 0x6d50:chǎn # 浐 0x6d51:hún # 浑 0x6d52:hǔ,xǔ # 浒 0x6d53:nóng # 浓 0x6d54:xún # 浔 0x6d55:jìn # 浕 0x6d56:liè # 浖 0x6d57:qiú # 浗 0x6d58:wěi # 浘 0x6d59:zhè # 浙 0x6d5a:jùn,xùn # 浚 0x6d5b:hán # 浛 0x6d5c:bāng # 浜 0x6d5d:máng # 浝 0x6d5e:zhuó # 浞 0x6d5f:yōu,dí # 浟 0x6d60:xī # 浠 0x6d61:bó # 浡 0x6d62:dòu # 浢 0x6d63:huàn # 浣 0x6d64:hóng # 浤 0x6d65:yì # 浥 0x6d66:pǔ # 浦 0x6d67:yǐng,chéng,yíng # 浧 0x6d68:lǎn # 浨 0x6d69:hào # 浩 0x6d6a:làng # 浪 0x6d6b:hǎn # 浫 0x6d6c:lǐ # 浬 0x6d6d:gēng # 浭 0x6d6e:fú # 浮 0x6d6f:wú # 浯 0x6d70:lì # 浰 0x6d71:chún # 浱 0x6d72:féng,hóng # 浲 0x6d73:yì # 浳 0x6d74:yù # 浴 0x6d75:tóng # 浵 0x6d76:láo # 浶 0x6d77:hǎi # 海 0x6d78:jìn # 浸 0x6d79:jiā # 浹 0x6d7a:chōng # 浺 0x6d7b:jiǒng,jiōng # 浻 0x6d7c:měi # 浼 0x6d7d:suī,něi # 浽 0x6d7e:chēng # 浾 0x6d7f:pèi # 浿 0x6d80:xiàn # 涀 0x6d81:shèn # 涁 0x6d82:tú # 涂 0x6d83:kùn # 涃 0x6d84:pīng # 涄 0x6d85:niè # 涅 0x6d86:hàn # 涆 0x6d87:jīng # 涇 0x6d88:xiāo # 消 0x6d89:shè # 涉 0x6d8a:niǎn # 涊 0x6d8b:tū # 涋 0x6d8c:yǒng,chōng # 涌 0x6d8d:xiào # 涍 0x6d8e:xián # 涎 0x6d8f:tǐng # 涏 0x6d90:é # 涐 0x6d91:sù # 涑 0x6d92:tūn,yūn # 涒 0x6d93:juān # 涓 0x6d94:cén # 涔 0x6d95:tì # 涕 0x6d96:lì # 涖 0x6d97:shuì # 涗 0x6d98:sì # 涘 0x6d99:lèi # 涙 0x6d9a:shuì # 涚 0x6d9b:tāo # 涛 0x6d9c:dú # 涜 0x6d9d:lào # 涝 0x6d9e:lái # 涞 0x6d9f:lián # 涟 0x6da0:wéi # 涠 0x6da1:wō,guō # 涡 0x6da2:yún # 涢 0x6da3:huàn # 涣 0x6da4:dí # 涤 0x6da6:rùn # 润 0x6da7:jiàn # 涧 0x6da8:zhǎng,zhàng # 涨 0x6da9:sè # 涩 0x6daa:fú # 涪 0x6dab:guān # 涫 0x6dac:xìng # 涬 0x6dad:shòu,tāo # 涭 0x6dae:shuàn # 涮 0x6daf:yá # 涯 0x6db0:chuò # 涰 0x6db1:zhàng # 涱 0x6db2:yè # 液 0x6db3:kōng,náng # 涳 0x6db4:wǎn,wò,yuān # 涴 0x6db5:hán # 涵 0x6db6:tuō,tuò # 涶 0x6db7:dōng # 涷 0x6db8:hé # 涸 0x6db9:wō # 涹 0x6dba:jū # 涺 0x6dbb:shè # 涻 0x6dbc:liáng,liàng # 涼 0x6dbd:hūn # 涽 0x6dbe:tà # 涾 0x6dbf:zhuō # 涿 0x6dc0:diàn # 淀 0x6dc1:qiè,jí # 淁 0x6dc2:dé # 淂 0x6dc3:juàn # 淃 0x6dc4:zī # 淄 0x6dc5:xī # 淅 0x6dc6:xiáo # 淆 0x6dc7:qí # 淇 0x6dc8:gǔ # 淈 0x6dc9:guǒ,guàn # 淉 0x6dca:yān # 淊 0x6dcb:lín,lìn # 淋 0x6dcc:tǎng,chǎng # 淌 0x6dcd:zhōu # 淍 0x6dce:pěng # 淎 0x6dcf:hào # 淏 0x6dd0:chāng # 淐 0x6dd1:shū # 淑 0x6dd2:qī # 淒 0x6dd3:fāng # 淓 0x6dd4:zhí # 淔 0x6dd5:lù # 淕 0x6dd6:nào,chuò,zhuō # 淖 0x6dd7:jú # 淗 0x6dd8:táo # 淘 0x6dd9:cóng # 淙 0x6dda:lèi # 淚 0x6ddb:zhè # 淛 0x6ddc:píng,péng # 淜 0x6ddd:féi # 淝 0x6dde:sōng # 淞 0x6ddf:tiǎn # 淟 0x6de0:pì,pèi # 淠 0x6de1:dàn # 淡 0x6de2:yù,xù # 淢 0x6de3:ní # 淣 0x6de4:yū # 淤 0x6de5:lù # 淥 0x6de6:gàn # 淦 0x6de7:mì # 淧 0x6de8:jìng,chēng # 淨 0x6de9:líng # 淩 0x6dea:lún # 淪 0x6deb:yín # 淫 0x6dec:cuì # 淬 0x6ded:qú # 淭 0x6dee:huái # 淮 0x6def:yù # 淯 0x6df0:niǎn,shěn # 淰 0x6df1:shēn # 深 0x6df2:biāo,hǔ # 淲 0x6df3:chún,zhūn # 淳 0x6df4:hū # 淴 0x6df5:yuān # 淵 0x6df6:lái # 淶 0x6df7:hùn,hún # 混 0x6df8:qīng # 淸 0x6df9:yān # 淹 0x6dfa:qiǎn # 淺 0x6dfb:tiān # 添 0x6dfc:miǎo # 淼 0x6dfd:zhǐ # 淽 0x6dfe:yǐn # 淾 0x6dff:bó # 淿 0x6e00:bèn # 渀 0x6e01:yuān # 渁 0x6e02:wèn,mín # 渂 0x6e03:ruò,rè,luò # 渃 0x6e04:fēi # 渄 0x6e05:qīng # 清 0x6e06:yuān # 渆 0x6e07:kě # 渇 0x6e08:jì,jǐ # 済 0x6e09:shè # 渉 0x6e0a:yuān # 渊 0x6e0c:lù # 渌 0x6e0d:zì # 渍 0x6e0e:dú,dòu # 渎 0x6e10:jiàn,jiān # 渐 0x6e11:miǎn,shéng # 渑 0x6e12:pài # 渒 0x6e14:yú # 渔 0x6e15:yuān # 渕 0x6e16:shěn # 渖 0x6e17:shèn # 渗 0x6e18:róu # 渘 0x6e19:huàn # 渙 0x6e1a:zhǔ # 渚 0x6e1b:jiǎn # 減 0x6e1c:nuǎn,nuán # 渜 0x6e1d:yú # 渝 0x6e1e:qiú,wù # 渞 0x6e1f:tíng,tīng # 渟 0x6e20:qú,jù # 渠 0x6e21:dù # 渡 0x6e22:fēng # 渢 0x6e23:zhā # 渣 0x6e24:bó # 渤 0x6e25:wò # 渥 0x6e26:wō,guō # 渦 0x6e27:tí,dī,dì # 渧 0x6e28:wěi # 渨 0x6e29:wēn # 温 0x6e2a:rú # 渪 0x6e2b:xiè # 渫 0x6e2c:cè # 測 0x6e2d:wèi # 渭 0x6e2e:hé # 渮 0x6e2f:gǎng,jiǎng # 港 0x6e30:yān,yǎn # 渰 0x6e31:hóng # 渱 0x6e32:xuàn # 渲 0x6e33:mǐ # 渳 0x6e34:kě # 渴 0x6e35:máo # 渵 0x6e36:yīng # 渶 0x6e37:yǎn # 渷 0x6e38:yóu # 游 0x6e39:hōng,qìng # 渹 0x6e3a:miǎo # 渺 0x6e3b:shěng # 渻 0x6e3c:měi # 渼 0x6e3d:zāi # 渽 0x6e3e:hún # 渾 0x6e3f:nài # 渿 0x6e40:guǐ # 湀 0x6e41:chì # 湁 0x6e42:è # 湂 0x6e43:pài # 湃 0x6e44:méi # 湄 0x6e45:liàn # 湅 0x6e46:qì # 湆 0x6e47:qì # 湇 0x6e48:méi # 湈 0x6e49:tián # 湉 0x6e4a:còu # 湊 0x6e4b:wéi # 湋 0x6e4c:cān # 湌 0x6e4d:tuān # 湍 0x6e4e:miǎn # 湎 0x6e4f:huì,mǐn,xū # 湏 0x6e50:pò # 湐 0x6e51:xǔ,xū # 湑 0x6e52:jí # 湒 0x6e53:pén # 湓 0x6e54:jiān # 湔 0x6e55:jiǎn # 湕 0x6e56:hú # 湖 0x6e57:fèng # 湗 0x6e58:xiāng # 湘 0x6e59:yì # 湙 0x6e5a:yìn # 湚 0x6e5b:zhàn # 湛 0x6e5c:shí # 湜 0x6e5d:jiē # 湝 0x6e5e:zhēn # 湞 0x6e5f:huáng # 湟 0x6e60:tàn # 湠 0x6e61:yú # 湡 0x6e62:bì # 湢 0x6e63:mǐn,hūn # 湣 0x6e64:shī # 湤 0x6e65:tū # 湥 0x6e66:shēng # 湦 0x6e67:yǒng # 湧 0x6e68:jú # 湨 0x6e69:dòng # 湩 0x6e6b:qiū,jiǎo # 湫 0x6e6c:qiū,jiǎo # 湬 0x6e6e:yān,yīn # 湮 0x6e6f:tāng,shāng # 湯 0x6e70:lóng # 湰 0x6e71:huò # 湱 0x6e72:yuán # 湲 0x6e73:nǎn # 湳 0x6e74:bàn,pán # 湴 0x6e75:yǒu # 湵 0x6e76:quán # 湶 0x6e77:zhuāng,hún # 湷 0x6e78:liàng # 湸 0x6e79:chán # 湹 0x6e7a:xián # 湺 0x6e7b:chún # 湻 0x6e7c:niè # 湼 0x6e7d:zī # 湽 0x6e7e:wān # 湾 0x6e7f:shī # 湿 0x6e80:mǎn # 満 0x6e81:yíng # 溁 0x6e83:kuì,huì # 溃 0x6e85:jiàn,jiān # 溅 0x6e86:xù # 溆 0x6e87:lóu # 溇 0x6e88:wéi # 溈 0x6e89:gài # 溉 0x6e8c:pō # 溌 0x6e8d:jìn # 溍 0x6e8e:yàn,guì # 溎 0x6e8f:táng # 溏 0x6e90:yuán # 源 0x6e91:suǒ # 溑 0x6e92:yuán # 溒 0x6e93:lián,liǎn,nián,xián,xiàn # 溓 0x6e94:yǎo # 溔 0x6e95:méng # 溕 0x6e96:zhǔn # 準 0x6e97:chéng # 溗 0x6e98:kè # 溘 0x6e99:tài # 溙 0x6e9a:dá,tǎ # 溚 0x6e9b:wā # 溛 0x6e9c:liū,liù # 溜 0x6e9d:gōu # 溝 0x6e9e:sāo # 溞 0x6e9f:míng # 溟 0x6ea0:zhà # 溠 0x6ea1:shí # 溡 0x6ea2:yì # 溢 0x6ea3:lùn # 溣 0x6ea4:mǎ # 溤 0x6ea5:pǔ # 溥 0x6ea6:wēi # 溦 0x6ea7:lì # 溧 0x6ea8:zāi # 溨 0x6ea9:wù # 溩 0x6eaa:xī # 溪 0x6eab:wēn # 溫 0x6eac:qiāng # 溬 0x6ead:zé # 溭 0x6eae:shī # 溮 0x6eaf:sù # 溯 0x6eb0:ái # 溰 0x6eb1:zhēn,qín # 溱 0x6eb2:sōu # 溲 0x6eb3:yún # 溳 0x6eb4:xiù # 溴 0x6eb5:yīn # 溵 0x6eb6:róng # 溶 0x6eb7:hùn # 溷 0x6eb8:sù # 溸 0x6eb9:suò # 溹 0x6eba:nì,niào # 溺 0x6ebb:tā # 溻 0x6ebc:shī # 溼 0x6ebd:rù # 溽 0x6ebe:āi # 溾 0x6ebf:pàn # 溿 0x6ec0:chù,xù # 滀 0x6ec1:chú # 滁 0x6ec2:pāng # 滂 0x6ec3:wěng,wēng # 滃 0x6ec4:cāng # 滄 0x6ec5:miè # 滅 0x6ec6:gé # 滆 0x6ec7:diān # 滇 0x6ec8:hào,xuè # 滈 0x6ec9:huàng # 滉 0x6eca:qì,xì,xiē # 滊 0x6ecb:zī # 滋 0x6ecc:dí # 滌 0x6ecd:zhì # 滍 0x6ece:xíng,yíng # 滎 0x6ecf:fǔ # 滏 0x6ed0:jié # 滐 0x6ed1:huá # 滑 0x6ed2:gē # 滒 0x6ed3:zǐ # 滓 0x6ed4:tāo # 滔 0x6ed5:téng # 滕 0x6ed6:suī # 滖 0x6ed7:bì # 滗 0x6ed8:jiào # 滘 0x6ed9:huì # 滙 0x6eda:gǔn # 滚 0x6edb:yín # 滛 0x6edc:zé,hào # 滜 0x6edd:lóng # 滝 0x6ede:zhì # 滞 0x6edf:yàn # 滟 0x6ee0:shè # 滠 0x6ee1:mǎn # 满 0x6ee2:yíng # 滢 0x6ee3:chún # 滣 0x6ee4:lǜ # 滤 0x6ee5:làn # 滥 0x6ee6:luán # 滦 0x6ee8:bīn # 滨 0x6ee9:tān # 滩 0x6eea:yù # 滪 0x6eeb:xiǔ # 滫 0x6eec:hù # 滬 0x6eed:bì # 滭 0x6eee:biāo # 滮 0x6eef:zhì # 滯 0x6ef0:jiàng # 滰 0x6ef1:kòu # 滱 0x6ef2:shèn # 滲 0x6ef3:shāng # 滳 0x6ef4:dī # 滴 0x6ef5:mì # 滵 0x6ef6:áo # 滶 0x6ef7:lǔ # 滷 0x6ef8:hǔ,xǔ # 滸 0x6ef9:hū # 滹 0x6efa:yōu # 滺 0x6efb:chǎn # 滻 0x6efc:fàn # 滼 0x6efd:yōng # 滽 0x6efe:gǔn # 滾 0x6eff:mǎn # 滿 0x6f00:qǐng # 漀 0x6f01:yú # 漁 0x6f02:piāo,piǎo,piào # 漂 0x6f03:jì # 漃 0x6f04:yá # 漄 0x6f05:cháo # 漅 0x6f06:qī # 漆 0x6f07:xǐ # 漇 0x6f08:jì # 漈 0x6f09:lù # 漉 0x6f0a:lóu # 漊 0x6f0b:lóng # 漋 0x6f0c:jǐn # 漌 0x6f0d:guó # 漍 0x6f0e:cóng,sǒng # 漎 0x6f0f:lòu # 漏 0x6f10:zhí # 漐 0x6f11:gài # 漑 0x6f12:qiáng # 漒 0x6f13:lí # 漓 0x6f14:yǎn # 演 0x6f15:cáo # 漕 0x6f16:jiào # 漖 0x6f17:cōng # 漗 0x6f18:chún # 漘 0x6f19:tuán,zhuān # 漙 0x6f1a:òu,ōu # 漚 0x6f1b:téng # 漛 0x6f1c:yě # 漜 0x6f1d:xí # 漝 0x6f1e:mì # 漞 0x6f1f:táng # 漟 0x6f20:mò # 漠 0x6f21:shāng # 漡 0x6f22:hàn # 漢 0x6f23:lián # 漣 0x6f24:lǎn # 漤 0x6f25:wā # 漥 0x6f26:chí # 漦 0x6f27:gān # 漧 0x6f28:féng,péng # 漨 0x6f29:xuán # 漩 0x6f2a:yī # 漪 0x6f2b:màn # 漫 0x6f2c:zì # 漬 0x6f2d:mǎng # 漭 0x6f2e:kāng # 漮 0x6f2f:luò,tà # 漯 0x6f30:bēn,pēng # 漰 0x6f31:shù # 漱 0x6f32:zhǎng,zhàng # 漲 0x6f33:zhāng # 漳 0x6f34:chóng,zhuàng # 漴 0x6f35:xù # 漵 0x6f36:huàn # 漶 0x6f37:huǒ,huò,kuò # 漷 0x6f38:jiàn,jiān # 漸 0x6f39:yān # 漹 0x6f3a:shuǎng # 漺 0x6f3b:liáo,liú # 漻 0x6f3c:cuǐ,cuī # 漼 0x6f3d:tí # 漽 0x6f3e:yàng # 漾 0x6f3f:jiāng,jiàng # 漿 0x6f40:cóng,zǒng # 潀 0x6f41:yǐng # 潁 0x6f42:hóng # 潂 0x6f43:xiǔ # 潃 0x6f44:shù # 潄 0x6f45:guàn # 潅 0x6f46:yíng # 潆 0x6f47:xiāo # 潇 0x6f4a:xù # 潊 0x6f4b:liàn # 潋 0x6f4c:zhì # 潌 0x6f4d:wéi # 潍 0x6f4e:pì,piē # 潎 0x6f4f:yù # 潏 0x6f50:jiào,qiáo # 潐 0x6f51:pō # 潑 0x6f52:dàng,xiàng # 潒 0x6f53:huì # 潓 0x6f54:jié # 潔 0x6f55:wǔ # 潕 0x6f56:pá # 潖 0x6f57:jí # 潗 0x6f58:pān # 潘 0x6f59:wéi # 潙 0x6f5a:sù # 潚 0x6f5b:qián # 潛 0x6f5c:qián # 潜 0x6f5d:xī,yà # 潝 0x6f5e:lù # 潞 0x6f5f:xì # 潟 0x6f60:xùn,sùn # 潠 0x6f61:dùn # 潡 0x6f62:huáng,guāng # 潢 0x6f63:mǐn # 潣 0x6f64:rùn # 潤 0x6f65:sù # 潥 0x6f66:lǎo,lào,liáo # 潦 0x6f67:zhēn # 潧 0x6f68:cōng,zòng # 潨 0x6f69:yì # 潩 0x6f6a:zhí,zhì # 潪 0x6f6b:wān # 潫 0x6f6c:tān,shàn # 潬 0x6f6d:tán # 潭 0x6f6e:cháo # 潮 0x6f6f:xún # 潯 0x6f70:kuì,huì # 潰 0x6f72:shào # 潲 0x6f73:tú,zhā # 潳 0x6f74:zhū # 潴 0x6f75:sàn,sǎ # 潵 0x6f76:hēi # 潶 0x6f77:bì # 潷 0x6f78:shān # 潸 0x6f79:chán # 潹 0x6f7a:chán # 潺 0x6f7b:shǔ # 潻 0x6f7c:tóng # 潼 0x6f7d:pū # 潽 0x6f7e:lín # 潾 0x6f7f:wéi # 潿 0x6f80:sè # 澀 0x6f81:sè # 澁 0x6f82:chéng # 澂 0x6f83:jiǒng # 澃 0x6f84:chéng,dèng # 澄 0x6f85:huà # 澅 0x6f86:jiāo # 澆 0x6f87:lào # 澇 0x6f88:chè # 澈 0x6f89:gǎn # 澉 0x6f8a:cūn,cún # 澊 0x6f8b:jǐng # 澋 0x6f8c:sī # 澌 0x6f8d:shù,zhù # 澍 0x6f8e:péng # 澎 0x6f8f:hán # 澏 0x6f90:yún # 澐 0x6f91:liū,liù # 澑 0x6f92:hòng,gǒng # 澒 0x6f93:fú # 澓 0x6f94:hào # 澔 0x6f95:hé # 澕 0x6f96:xián # 澖 0x6f97:jiàn # 澗 0x6f98:shān # 澘 0x6f99:xì # 澙 0x6f9c:lán # 澜 0x6f9e:yú # 澞 0x6f9f:lǐn # 澟 0x6fa0:miǎn,shéng # 澠 0x6fa1:zǎo # 澡 0x6fa2:dāng # 澢 0x6fa3:huàn # 澣 0x6fa4:zé,shì # 澤 0x6fa5:xiè # 澥 0x6fa6:yù # 澦 0x6fa7:lǐ # 澧 0x6fa8:shì # 澨 0x6fa9:xué # 澩 0x6faa:líng # 澪 0x6fab:wàn,màn # 澫 0x6fac:zī # 澬 0x6fad:yōng,yǒng # 澭 0x6fae:kuài,huì # 澮 0x6faf:càn # 澯 0x6fb0:liàn # 澰 0x6fb1:diàn # 澱 0x6fb2:yè # 澲 0x6fb3:ào # 澳 0x6fb4:huán # 澴 0x6fb5:zhēn # 澵 0x6fb6:chán # 澶 0x6fb7:màn # 澷 0x6fb8:gǎn # 澸 0x6fb9:dàn,tán # 澹 0x6fba:yì # 澺 0x6fbb:suì # 澻 0x6fbc:pì # 澼 0x6fbd:jù # 澽 0x6fbe:tà # 澾 0x6fbf:qín # 澿 0x6fc0:jī # 激 0x6fc1:zhuó # 濁 0x6fc2:lián # 濂 0x6fc3:nóng # 濃 0x6fc4:guō,wō # 濄 0x6fc5:jìn # 濅 0x6fc6:fén,pēn # 濆 0x6fc7:sè # 濇 0x6fc8:jí,shà # 濈 0x6fc9:suī # 濉 0x6fca:huì,huò # 濊 0x6fcb:chǔ # 濋 0x6fcc:tà # 濌 0x6fcd:sōng # 濍 0x6fce:dǐng,tìng # 濎 0x6fd0:zhǔ # 濐 0x6fd1:lài # 濑 0x6fd2:bīn # 濒 0x6fd3:lián # 濓 0x6fd4:mǐ,nǐ # 濔 0x6fd5:shī # 濕 0x6fd6:shù # 濖 0x6fd7:mì # 濗 0x6fd8:nìng # 濘 0x6fd9:yíng # 濙 0x6fda:yíng # 濚 0x6fdb:méng # 濛 0x6fdc:jìn # 濜 0x6fdd:qí # 濝 0x6fde:bì,pì # 濞 0x6fdf:jì,jǐ # 濟 0x6fe0:háo # 濠 0x6fe1:rú # 濡 0x6fe2:cuì,zuǐ # 濢 0x6fe3:wò # 濣 0x6fe4:tāo # 濤 0x6fe5:yǐn # 濥 0x6fe6:yīn # 濦 0x6fe7:duì # 濧 0x6fe8:cí # 濨 0x6fe9:huò,hù # 濩 0x6fea:qìng # 濪 0x6feb:làn # 濫 0x6fec:jùn,xùn # 濬 0x6fed:ǎi,kài,kè # 濭 0x6fee:pú # 濮 0x6fef:zhuó,zhào # 濯 0x6ff0:wéi # 濰 0x6ff1:bīn # 濱 0x6ff2:gǔ # 濲 0x6ff3:qián # 濳 0x6ff4:yíng # 濴 0x6ff6:kuò # 濶 0x6ff7:fèi # 濷 0x6ffa:jiàn,jiān # 濺 0x6ffb:wěi,duì # 濻 0x6ffc:luò,pō # 濼 0x6ffd:zàn,cuán # 濽 0x6ffe:lǜ # 濾 0x6fff:lì # 濿 0x7000:yōu # 瀀 0x7001:yǎng,yàng # 瀁 0x7002:lǔ # 瀂 0x7003:sì # 瀃 0x7004:zhì # 瀄 0x7005:yíng # 瀅 0x7006:dú,dòu # 瀆 0x7007:wǎng,wāng # 瀇 0x7008:huī # 瀈 0x7009:xiè # 瀉 0x700a:pán # 瀊 0x700b:shěn # 瀋 0x700c:biāo # 瀌 0x700d:chán # 瀍 0x700e:miè,mò # 瀎 0x700f:liú # 瀏 0x7010:jiān # 瀐 0x7011:pù,bào # 瀑 0x7012:sè # 瀒 0x7013:chéng,dèng # 瀓 0x7014:gǔ # 瀔 0x7015:bīn # 瀕 0x7016:huò # 瀖 0x7017:xiàn # 瀗 0x7018:lú # 瀘 0x7019:qìn # 瀙 0x701a:hàn # 瀚 0x701b:yíng # 瀛 0x701c:róng # 瀜 0x701d:lì # 瀝 0x701e:jìng # 瀞 0x701f:xiāo # 瀟 0x7020:yíng # 瀠 0x7021:suǐ # 瀡 0x7022:wěi,duì # 瀢 0x7023:xiè # 瀣 0x7024:huái,wāi # 瀤 0x7025:xuè # 瀥 0x7026:zhū # 瀦 0x7027:lóng,shuāng # 瀧 0x7028:lài # 瀨 0x7029:duì # 瀩 0x702a:fàn # 瀪 0x702b:hú # 瀫 0x702c:lài # 瀬 0x702f:yíng # 瀯 0x7030:mí # 瀰 0x7031:jì # 瀱 0x7032:liàn # 瀲 0x7033:jiàn,zùn # 瀳 0x7034:yīng,yǐng,yìng # 瀴 0x7035:fèn # 瀵 0x7036:lín # 瀶 0x7037:yì # 瀷 0x7038:jiān # 瀸 0x7039:yuè # 瀹 0x703a:chán # 瀺 0x703b:dài # 瀻 0x703c:ráng,nǎng # 瀼 0x703d:jiǎn # 瀽 0x703e:lán # 瀾 0x703f:fán # 瀿 0x7040:shuàng # 灀 0x7041:yuān # 灁 0x7042:zhuó,jiào,zé # 灂 0x7043:fēng # 灃 0x7044:shè # 灄 0x7045:lěi # 灅 0x7046:lán # 灆 0x7047:cóng # 灇 0x7048:qú # 灈 0x7049:yōng # 灉 0x704a:qián # 灊 0x704b:fǎ # 灋 0x704c:guàn # 灌 0x704d:jué # 灍 0x704e:yàn # 灎 0x704f:hào # 灏 0x7051:sǎ # 灑 0x7052:zàn,cuán # 灒 0x7053:luán,luàn # 灓 0x7054:yàn # 灔 0x7055:lí # 灕 0x7056:mǐ # 灖 0x7057:shàn # 灗 0x7058:tān # 灘 0x7059:dǎng,tǎng # 灙 0x705a:jiǎo # 灚 0x705b:chǎn # 灛 0x705d:hào # 灝 0x705e:bà # 灞 0x705f:zhú # 灟 0x7060:lǎn # 灠 0x7061:lán # 灡 0x7062:nǎng # 灢 0x7063:wān # 灣 0x7064:luán # 灤 0x7065:xún,quán,quàn # 灥 0x7066:xiǎn # 灦 0x7067:yàn # 灧 0x7068:gàn # 灨 0x7069:yàn # 灩 0x706a:yù # 灪 0x706b:huǒ # 火 0x706c:huǒ,biāo # 灬 0x706d:miè # 灭 0x706e:guāng # 灮 0x706f:dēng # 灯 0x7070:huī # 灰 0x7071:xiāo # 灱 0x7072:xiāo # 灲 0x7074:hōng # 灴 0x7075:líng # 灵 0x7076:zào # 灶 0x7077:zhuàn # 灷 0x7078:jiǔ # 灸 0x7079:zhà,yù # 灹 0x707a:xiè # 灺 0x707b:chì # 灻 0x707c:zhuó # 灼 0x707d:zāi # 災 0x707e:zāi # 灾 0x707f:càn # 灿 0x7080:yáng # 炀 0x7081:qì # 炁 0x7082:zhōng # 炂 0x7083:fén,bèn # 炃 0x7084:niǔ # 炄 0x7085:jiǒng,guì # 炅 0x7086:wén # 炆 0x7087:pū # 炇 0x7088:yì # 炈 0x7089:lú # 炉 0x708a:chuī # 炊 0x708b:pī # 炋 0x708c:kài # 炌 0x708d:pàn # 炍 0x708e:yán # 炎 0x708f:yán # 炏 0x7090:pàng,fēng # 炐 0x7091:mù # 炑 0x7092:chǎo # 炒 0x7093:liào # 炓 0x7094:quē,guì # 炔 0x7095:kàng # 炕 0x7096:dùn # 炖 0x7097:guāng # 炗 0x7098:xìn # 炘 0x7099:zhì # 炙 0x709b:guāng # 炛 0x709c:wěi # 炜 0x709d:qiàng # 炝 0x709f:dá # 炟 0x70a0:xiá # 炠 0x70a1:zhēng # 炡 0x70a2:zhú # 炢 0x70a3:kě # 炣 0x70a4:zhào,zhāo # 炤 0x70a5:fú # 炥 0x70a6:bá # 炦 0x70a7:xiè # 炧 0x70a8:xiè # 炨 0x70a9:lìng # 炩 0x70aa:zhuō,chù # 炪 0x70ab:xuàn # 炫 0x70ac:jù # 炬 0x70ad:tàn # 炭 0x70ae:páo,bāo,pào # 炮 0x70af:jiǒng # 炯 0x70b0:páo,fǒu # 炰 0x70b1:tái # 炱 0x70b2:tái # 炲 0x70b3:bǐng # 炳 0x70b4:yǎng # 炴 0x70b5:tōng # 炵 0x70b6:shǎn,qián,shān # 炶 0x70b7:zhù # 炷 0x70b8:zhà,zhá # 炸 0x70b9:diǎn # 点 0x70ba:wéi,wèi # 為 0x70bb:shí # 炻 0x70bc:liàn # 炼 0x70bd:chì # 炽 0x70be:huǎng # 炾 0x70c0:hū # 烀 0x70c1:shuò # 烁 0x70c2:làn # 烂 0x70c3:tīng # 烃 0x70c4:jiǎo,yào # 烄 0x70c5:xù # 烅 0x70c6:héng # 烆 0x70c7:quǎn # 烇 0x70c8:liè # 烈 0x70c9:huàn # 烉 0x70ca:yáng,yàng # 烊 0x70cb:xiāo # 烋 0x70cc:xiū # 烌 0x70cd:xiǎn # 烍 0x70ce:yín # 烎 0x70cf:wū # 烏 0x70d0:zhōu # 烐 0x70d1:yáo # 烑 0x70d2:shì # 烒 0x70d3:wēi # 烓 0x70d4:tóng,dòng # 烔 0x70d5:miè # 烕 0x70d6:zāi # 烖 0x70d7:kài # 烗 0x70d8:hōng # 烘 0x70d9:lào,luò # 烙 0x70da:xiá # 烚 0x70db:zhú # 烛 0x70dc:xuǎn # 烜 0x70dd:zhēng # 烝 0x70de:pò # 烞 0x70df:yān # 烟 0x70e0:huí,huǐ # 烠 0x70e1:guāng # 烡 0x70e2:chè # 烢 0x70e3:huī # 烣 0x70e4:kǎo # 烤 0x70e6:fán # 烦 0x70e7:shāo # 烧 0x70e8:yè # 烨 0x70e9:huì # 烩 0x70eb:tàng # 烫 0x70ec:jìn # 烬 0x70ed:rè # 热 0x70ef:xī # 烯 0x70f0:fú,páo # 烰 0x70f1:jiǒng # 烱 0x70f2:xiè,chè # 烲 0x70f3:pǔ # 烳 0x70f4:tīng # 烴 0x70f5:zhuó # 烵 0x70f6:tǐng # 烶 0x70f7:wán # 烷 0x70f8:hǎi # 烸 0x70f9:pēng # 烹 0x70fa:lǎng # 烺 0x70fb:yàn # 烻 0x70fc:xù # 烼 0x70fd:fēng # 烽 0x70fe:chì # 烾 0x70ff:róng # 烿 0x7100:hú # 焀 0x7102:shū # 焂 0x7103:hè # 焃 0x7104:xūn,hūn # 焄 0x7105:kù # 焅 0x7106:juān,yè # 焆 0x7107:xiāo # 焇 0x7108:xī # 焈 0x7109:yān # 焉 0x710a:hàn # 焊 0x710b:zhuàng # 焋 0x710c:qū,jùn # 焌 0x710d:dì # 焍 0x710e:xiè,chè # 焎 0x710f:jí,qì # 焏 0x7110:wù # 焐 0x7113:hán # 焓 0x7114:yàn # 焔 0x7115:huàn # 焕 0x7116:mèn # 焖 0x7117:jú # 焗 0x7118:dào,tāo # 焘 0x7119:bèi # 焙 0x711a:fén # 焚 0x711b:lìn # 焛 0x711c:kūn # 焜 0x711d:hùn # 焝 0x711e:tūn # 焞 0x711f:xī # 焟 0x7120:cuì # 焠 0x7121:wú,mó # 無 0x7122:hōng # 焢 0x7123:chǎo,jù # 焣 0x7124:fǔ # 焤 0x7125:wò,ài # 焥 0x7126:jiāo # 焦 0x7127:zǒng,cōng # 焧 0x7128:fèng # 焨 0x7129:píng # 焩 0x712a:qióng # 焪 0x712b:ruò # 焫 0x712c:xī,yì # 焬 0x712d:qióng # 焭 0x712e:xìn # 焮 0x712f:zhuō,chāo # 焯 0x7130:yàn # 焰 0x7131:yàn # 焱 0x7132:yì # 焲 0x7133:jué # 焳 0x7134:yù # 焴 0x7135:gàng # 焵 0x7136:rán # 然 0x7137:pí # 焷 0x7138:xiǒng,yīng # 焸 0x713a:shēng # 焺 0x713b:chàng # 焻 0x713c:shāo # 焼 0x713f:gēng # 焿 0x7141:chén # 煁 0x7142:hè # 煂 0x7143:kuǐ # 煃 0x7144:zhǒng # 煄 0x7145:duàn # 煅 0x7146:xiā # 煆 0x7147:huī,yùn,xūn # 煇 0x7148:fèng # 煈 0x7149:liàn # 煉 0x714a:xuān # 煊 0x714b:xīng # 煋 0x714c:huáng # 煌 0x714d:jiǎo,qiāo # 煍 0x714e:jiān # 煎 0x714f:bì # 煏 0x7150:yīng # 煐 0x7151:zhǔ # 煑 0x7152:wěi # 煒 0x7153:tuān # 煓 0x7154:shǎn,qián,shān # 煔 0x7155:xī,yí # 煕 0x7156:nuǎn,xuān # 煖 0x7157:nuǎn # 煗 0x7158:chán # 煘 0x7159:yān # 煙 0x715a:jiǒng # 煚 0x715b:jiǒng # 煛 0x715c:yù # 煜 0x715d:mèi # 煝 0x715e:shā,shà # 煞 0x715f:wèi # 煟 0x7160:yè,zhá # 煠 0x7161:jìn # 煡 0x7162:qióng # 煢 0x7163:róu # 煣 0x7164:méi # 煤 0x7165:huàn # 煥 0x7166:xù # 煦 0x7167:zhào # 照 0x7168:wēi # 煨 0x7169:fán # 煩 0x716a:qiú # 煪 0x716b:suì # 煫 0x716c:yáng,yàng # 煬 0x716d:liè # 煭 0x716e:zhǔ # 煮 0x7170:zào # 煰 0x7171:guā # 煱 0x7172:bāo # 煲 0x7173:hú # 煳 0x7174:yūn,yǔn # 煴 0x7175:nǎn # 煵 0x7178:biān # 煸 0x7179:gòu # 煹 0x717a:tuì # 煺 0x717b:táng # 煻 0x717c:chǎo # 煼 0x717d:shān # 煽 0x717e:ēn,yūn # 煾 0x717f:bó # 煿 0x7180:huǎng # 熀 0x7181:xié # 熁 0x7182:xì # 熂 0x7183:wù # 熃 0x7184:xī # 熄 0x7185:yūn,yǔn # 熅 0x7186:hé # 熆 0x7187:hè,xiāo # 熇 0x7188:xī # 熈 0x7189:yún # 熉 0x718a:xióng # 熊 0x718b:xióng # 熋 0x718c:shǎn # 熌 0x718e:yào # 熎 0x718f:xūn,xùn # 熏 0x7190:mì # 熐 0x7191:lián # 熑 0x7192:yíng # 熒 0x7193:wǔ # 熓 0x7194:róng # 熔 0x7197:qiàng # 熗 0x7198:liū # 熘 0x7199:xī # 熙 0x719a:bì # 熚 0x719b:biāo # 熛 0x719c:cōng,zǒng # 熜 0x719d:lù,āo # 熝 0x719e:jiān # 熞 0x719f:shú,shóu # 熟 0x71a0:yì # 熠 0x71a1:lóu # 熡 0x71a2:péng,fēng # 熢 0x71a3:suī,cuǐ # 熣 0x71a4:yì # 熤 0x71a5:tēng,tōng # 熥 0x71a6:jué # 熦 0x71a7:zōng # 熧 0x71a8:yùn,yù # 熨 0x71a9:hù # 熩 0x71aa:yí # 熪 0x71ab:zhì # 熫 0x71ac:āo,áo # 熬 0x71ad:wèi # 熭 0x71ae:liǔ # 熮 0x71af:hàn,rǎn # 熯 0x71b0:ōu,ǒu # 熰 0x71b1:rè # 熱 0x71b2:jiǒng # 熲 0x71b3:màn # 熳 0x71b5:shāng # 熵 0x71b6:cuàn # 熶 0x71b7:zèng # 熷 0x71b8:jiān # 熸 0x71b9:xī # 熹 0x71ba:xī # 熺 0x71bb:xī # 熻 0x71bc:yì # 熼 0x71bd:xiào # 熽 0x71be:chì # 熾 0x71bf:huáng,huǎng # 熿 0x71c0:chǎn,dǎn,chàn # 燀 0x71c1:yè # 燁 0x71c2:tán # 燂 0x71c3:rán # 燃 0x71c4:yàn # 燄 0x71c5:xún # 燅 0x71c6:qiāo # 燆 0x71c7:jùn # 燇 0x71c8:dēng # 燈 0x71c9:dùn # 燉 0x71ca:shēn # 燊 0x71cb:jiāo,qiáo,jué,zhuó # 燋 0x71cc:fén # 燌 0x71cd:sī # 燍 0x71ce:liáo,liǎo # 燎 0x71cf:yù # 燏 0x71d0:lín # 燐 0x71d1:tóng,dòng # 燑 0x71d2:shāo # 燒 0x71d3:fén # 燓 0x71d4:fán # 燔 0x71d5:yàn,yān # 燕 0x71d6:xún # 燖 0x71d7:làn # 燗 0x71d8:měi # 燘 0x71d9:tàng # 燙 0x71da:yì # 燚 0x71db:jiǒng # 燛 0x71dc:mèn # 燜 0x71df:yíng # 營 0x71e0:yù # 燠 0x71e1:yì # 燡 0x71e2:xué # 燢 0x71e3:lán # 燣 0x71e4:tài,liè # 燤 0x71e5:zào # 燥 0x71e6:càn # 燦 0x71e7:suì # 燧 0x71e8:xī # 燨 0x71e9:què # 燩 0x71ea:zǒng # 燪 0x71eb:lián # 燫 0x71ec:huǐ # 燬 0x71ed:zhú # 燭 0x71ee:xiè # 燮 0x71ef:líng # 燯 0x71f0:wēi # 燰 0x71f1:yì # 燱 0x71f2:xié # 燲 0x71f3:zhào # 燳 0x71f4:huì # 燴 0x71f7:lán # 燷 0x71f8:xū # 燸 0x71f9:xiǎn # 燹 0x71fa:hè # 燺 0x71fb:xūn # 燻 0x71fc:jìn # 燼 0x71fd:chóu # 燽 0x71fe:dào,tāo # 燾 0x71ff:yào # 燿 0x7200:hè # 爀 0x7201:làn # 爁 0x7202:biāo # 爂 0x7203:róng,yíng # 爃 0x7204:lì,liè # 爄 0x7205:mò # 爅 0x7206:bào # 爆 0x7207:ruò # 爇 0x7208:lǜ # 爈 0x7209:là,liè # 爉 0x720a:āo # 爊 0x720b:xūn,xùn # 爋 0x720c:kuàng,huǎng # 爌 0x720d:shuò # 爍 0x720f:lì # 爏 0x7210:lú # 爐 0x7211:jué # 爑 0x7212:liáo,liǎo # 爒 0x7213:yàn,xún # 爓 0x7214:xī # 爔 0x7215:xiè # 爕 0x7216:lóng # 爖 0x7217:yè # 爗 0x7219:rǎng # 爙 0x721a:yuè # 爚 0x721b:làn # 爛 0x721c:cóng # 爜 0x721d:jué # 爝 0x721e:chóng # 爞 0x721f:guàn # 爟 0x7221:chè # 爡 0x7222:mí # 爢 0x7223:tǎng # 爣 0x7224:làn # 爤 0x7225:zhú # 爥 0x7227:líng # 爧 0x7228:cuàn # 爨 0x7229:yù # 爩 0x722a:zhǎo,zhuǎ # 爪 0x722c:pá # 爬 0x722d:zhēng # 爭 0x722e:páo # 爮 0x722f:chēng,chèn # 爯 0x7230:yuán # 爰 0x7231:ài # 爱 0x7232:wéi,wèi # 爲 0x7234:jué # 爴 0x7235:jué # 爵 0x7236:fù,fǔ # 父 0x7237:yé # 爷 0x7238:bà # 爸 0x7239:diē # 爹 0x723a:yé # 爺 0x723b:yáo # 爻 0x723c:zǔ # 爼 0x723d:shuǎng # 爽 0x723e:ěr # 爾 0x723f:pán # 爿 0x7240:chuáng # 牀 0x7241:kē # 牁 0x7242:zāng # 牂 0x7243:dié # 牃 0x7244:qiāng # 牄 0x7245:yōng # 牅 0x7246:qiáng # 牆 0x7247:piàn,piān # 片 0x7248:bǎn # 版 0x7249:pàn # 牉 0x724a:cháo # 牊 0x724b:jiān # 牋 0x724c:pái # 牌 0x724d:dú # 牍 0x724e:chuāng # 牎 0x724f:yú # 牏 0x7250:zhá # 牐 0x7251:biān,miàn # 牑 0x7252:dié # 牒 0x7253:bǎng # 牓 0x7254:bó # 牔 0x7255:chuāng # 牕 0x7256:yǒu # 牖 0x7258:dú # 牘 0x7259:yá # 牙 0x725a:chēng,chèng # 牚 0x725b:niú # 牛 0x725d:pìn # 牝 0x725e:jiū,lè # 牞 0x725f:móu,mù # 牟 0x7260:tā # 牠 0x7261:mǔ # 牡 0x7262:láo # 牢 0x7263:rèn # 牣 0x7264:māng # 牤 0x7265:fāng # 牥 0x7266:máo # 牦 0x7267:mù # 牧 0x7268:gāng # 牨 0x7269:wù # 物 0x726a:yàn # 牪 0x726b:gē,qiú # 牫 0x726c:bèi # 牬 0x726d:sì # 牭 0x726e:jiàn # 牮 0x726f:gǔ # 牯 0x7270:yòu,chōu # 牰 0x7271:kē # 牱 0x7272:shēng # 牲 0x7273:mǔ # 牳 0x7274:dǐ # 牴 0x7275:qiān # 牵 0x7276:quàn # 牶 0x7277:quán # 牷 0x7278:zì # 牸 0x7279:tè # 特 0x727a:xī # 牺 0x727b:máng # 牻 0x727c:kēng # 牼 0x727d:qiān # 牽 0x727e:wǔ # 牾 0x727f:gù # 牿 0x7280:xī # 犀 0x7281:lí # 犁 0x7282:lí # 犂 0x7283:pǒu # 犃 0x7284:jī # 犄 0x7285:gāng # 犅 0x7286:zhí,tè # 犆 0x7287:bēn # 犇 0x7288:quán # 犈 0x7289:chún # 犉 0x728a:dú # 犊 0x728b:jù # 犋 0x728c:jiā # 犌 0x728d:jiān,qián # 犍 0x728e:fēng # 犎 0x728f:piān # 犏 0x7290:kē # 犐 0x7291:jú # 犑 0x7292:kào # 犒 0x7293:chú # 犓 0x7294:xì # 犔 0x7295:bèi # 犕 0x7296:luò # 犖 0x7297:jiè # 犗 0x7298:má # 犘 0x7299:sān # 犙 0x729a:wèi # 犚 0x729b:máo,lí # 犛 0x729c:dūn # 犜 0x729d:tóng # 犝 0x729f:jiàng # 犟 0x72a1:lì # 犡 0x72a2:dú # 犢 0x72a3:liè # 犣 0x72a4:pái # 犤 0x72a5:piāo # 犥 0x72a6:bào # 犦 0x72a7:xī # 犧 0x72a8:chōu # 犨 0x72a9:wéi # 犩 0x72aa:kuí # 犪 0x72ab:chōu # 犫 0x72ac:quǎn # 犬 0x72ae:quǎn,bá # 犮 0x72af:fàn # 犯 0x72b0:qiú # 犰 0x72b1:jǐ # 犱 0x72b2:chái # 犲 0x72b3:zhuó,bào # 犳 0x72b4:hān,àn # 犴 0x72b5:gē # 犵 0x72b6:zhuàng # 状 0x72b7:guǎng # 犷 0x72b8:mǎ # 犸 0x72b9:yóu # 犹 0x72ba:kàng,gǎng # 犺 0x72bb:pèi,fèi # 犻 0x72bc:hǒu # 犼 0x72bd:yà # 犽 0x72be:yín # 犾 0x72bf:huān,fān # 犿 0x72c0:zhuàng # 狀 0x72c1:yǔn # 狁 0x72c2:kuáng # 狂 0x72c3:niǔ # 狃 0x72c4:dí # 狄 0x72c5:kuáng # 狅 0x72c6:zhòng # 狆 0x72c7:mù # 狇 0x72c8:bèi # 狈 0x72c9:pī # 狉 0x72ca:jú # 狊 0x72cb:yí,quán,chí # 狋 0x72cc:shēng,xīng # 狌 0x72cd:páo # 狍 0x72ce:xiá # 狎 0x72cf:tuó,yí # 狏 0x72d0:hú # 狐 0x72d1:líng # 狑 0x72d2:fèi # 狒 0x72d3:pī # 狓 0x72d4:nǐ # 狔 0x72d5:yǎo # 狕 0x72d6:yòu # 狖 0x72d7:gǒu # 狗 0x72d8:xuè # 狘 0x72d9:jū # 狙 0x72da:dàn # 狚 0x72db:bó # 狛 0x72dc:kǔ # 狜 0x72dd:xiǎn # 狝 0x72de:níng # 狞 0x72df:huán,huān # 狟 0x72e0:hěn # 狠 0x72e1:jiǎo # 狡 0x72e2:hé,mò # 狢 0x72e3:zhào # 狣 0x72e4:jié # 狤 0x72e5:xùn # 狥 0x72e6:shān # 狦 0x72e7:tà,shì # 狧 0x72e8:róng # 狨 0x72e9:shòu # 狩 0x72ea:tóng,dòng # 狪 0x72eb:lǎo # 狫 0x72ec:dú # 独 0x72ed:xiá # 狭 0x72ee:shī # 狮 0x72ef:kuài # 狯 0x72f0:zhēng # 狰 0x72f1:yù # 狱 0x72f2:sūn # 狲 0x72f3:yú # 狳 0x72f4:bì # 狴 0x72f5:máng,dòu # 狵 0x72f6:xī,shǐ # 狶 0x72f7:juàn # 狷 0x72f8:lí # 狸 0x72f9:xiá # 狹 0x72fa:yín # 狺 0x72fb:suān # 狻 0x72fc:láng # 狼 0x72fd:bèi # 狽 0x72fe:zhì # 狾 0x72ff:yán # 狿 0x7300:shā # 猀 0x7301:lì # 猁 0x7302:hàn # 猂 0x7303:xiǎn # 猃 0x7304:jīng # 猄 0x7305:pái # 猅 0x7306:fēi # 猆 0x7307:xiāo # 猇 0x7308:bài,pí # 猈 0x7309:qí # 猉 0x730a:ní # 猊 0x730b:biāo # 猋 0x730c:yìn # 猌 0x730d:lái # 猍 0x730e:liè # 猎 0x730f:jiān,yàn # 猏 0x7310:qiāng # 猐 0x7311:kūn # 猑 0x7312:yàn # 猒 0x7313:guō # 猓 0x7314:zòng # 猔 0x7315:mí # 猕 0x7316:chāng # 猖 0x7317:yī,yǐ # 猗 0x7318:zhì # 猘 0x7319:zhēng # 猙 0x731a:yá,wèi # 猚 0x731b:měng # 猛 0x731c:cāi # 猜 0x731d:cù # 猝 0x731e:shē # 猞 0x7321:luó # 猡 0x7322:hú # 猢 0x7323:zōng # 猣 0x7324:guì # 猤 0x7325:wěi # 猥 0x7326:fēng # 猦 0x7327:wō # 猧 0x7328:yuán # 猨 0x7329:xīng # 猩 0x732a:zhū # 猪 0x732b:māo,máo # 猫 0x732c:wèi # 猬 0x732d:chuàn,chuān # 猭 0x732e:xiàn # 献 0x732f:tuān,tuàn # 猯 0x7330:yà,jiá,qiè # 猰 0x7331:náo # 猱 0x7332:xiē,hè,gé,hài # 猲 0x7333:jiā # 猳 0x7334:hóu # 猴 0x7335:biān,piàn # 猵 0x7336:yóu # 猶 0x7337:yóu # 猷 0x7338:méi # 猸 0x7339:chá # 猹 0x733a:yáo # 猺 0x733b:sūn # 猻 0x733c:bó,pò # 猼 0x733d:míng # 猽 0x733e:huá # 猾 0x733f:yuán # 猿 0x7340:sōu # 獀 0x7341:mǎ # 獁 0x7342:huán # 獂 0x7343:dāi # 獃 0x7344:yù # 獄 0x7345:shī # 獅 0x7346:háo # 獆 0x7348:yì # 獈 0x7349:zhēn # 獉 0x734a:cāng # 獊 0x734b:háo,gāo # 獋 0x734c:màn # 獌 0x734d:jìng # 獍 0x734e:jiǎng # 獎 0x734f:mò # 獏 0x7350:zhāng # 獐 0x7351:chán # 獑 0x7352:áo # 獒 0x7353:áo # 獓 0x7354:háo # 獔 0x7355:suǒ,cuī # 獕 0x7356:fén,fèn # 獖 0x7357:jué # 獗 0x7358:bì # 獘 0x7359:bì # 獙 0x735a:huáng # 獚 0x735b:pú # 獛 0x735c:lín,lìn # 獜 0x735d:xù # 獝 0x735e:tóng # 獞 0x735f:yào,xiāo # 獟 0x7360:liáo # 獠 0x7361:shuò,xī # 獡 0x7362:xiāo # 獢 0x7365:jiào # 獥 0x7366:gé,liè,xiē # 獦 0x7367:juàn # 獧 0x7368:dú # 獨 0x7369:huì # 獩 0x736a:kuài # 獪 0x736b:xiǎn # 獫 0x736c:xiè # 獬 0x736d:tǎ # 獭 0x736e:xiǎn # 獮 0x736f:xūn # 獯 0x7370:níng # 獰 0x7371:biān,piàn # 獱 0x7372:huò # 獲 0x7373:nòu,rú # 獳 0x7374:méng # 獴 0x7375:liè # 獵 0x7376:náo,nǎo,yōu # 獶 0x7377:guǎng # 獷 0x7378:shòu # 獸 0x7379:lú # 獹 0x737a:tǎ # 獺 0x737b:xiàn # 獻 0x737c:mí # 獼 0x737d:ráng # 獽 0x737e:huān # 獾 0x737f:náo,yōu # 獿 0x7380:luó # 玀 0x7381:xiǎn # 玁 0x7382:qí # 玂 0x7383:jué # 玃 0x7384:xuán # 玄 0x7385:miào # 玅 0x7386:zī # 玆 0x7387:shuài,lǜ # 率 0x7388:lú # 玈 0x7389:yù # 玉 0x738a:sù # 玊 0x738b:wáng,wàng # 王 0x738c:qiú # 玌 0x738d:gǎ # 玍 0x738e:dīng # 玎 0x738f:lè # 玏 0x7390:bā # 玐 0x7391:jī # 玑 0x7392:hóng # 玒 0x7393:dì # 玓 0x7394:chuàn # 玔 0x7395:gān # 玕 0x7396:jiǔ # 玖 0x7397:yú # 玗 0x7398:qǐ # 玘 0x7399:yú # 玙 0x739a:chàng,yáng # 玚 0x739b:mǎ # 玛 0x739c:hóng # 玜 0x739d:wǔ # 玝 0x739e:fū # 玞 0x739f:mín,wén # 玟 0x73a0:jiè # 玠 0x73a1:yà # 玡 0x73a2:bīn,fēn # 玢 0x73a3:biàn # 玣 0x73a4:bàng # 玤 0x73a5:yuè # 玥 0x73a6:jué # 玦 0x73a7:mén,yǔn # 玧 0x73a8:jué # 玨 0x73a9:wán # 玩 0x73aa:jiān,qián # 玪 0x73ab:méi # 玫 0x73ac:dǎn # 玬 0x73ad:pín # 玭 0x73ae:wěi # 玮 0x73af:huán # 环 0x73b0:xiàn # 现 0x73b1:qiāng,cāng # 玱 0x73b2:líng # 玲 0x73b3:dài # 玳 0x73b4:yì # 玴 0x73b5:án,gān # 玵 0x73b6:píng # 玶 0x73b7:diàn # 玷 0x73b8:fú # 玸 0x73b9:xuán,xián # 玹 0x73ba:xǐ # 玺 0x73bb:bō # 玻 0x73bc:cī,cǐ # 玼 0x73bd:gǒu # 玽 0x73be:jiǎ # 玾 0x73bf:sháo # 玿 0x73c0:pò # 珀 0x73c1:cí # 珁 0x73c2:kē # 珂 0x73c3:rǎn # 珃 0x73c4:shēng # 珄 0x73c5:shēn # 珅 0x73c6:yí,tāi # 珆 0x73c7:zǔ,jù # 珇 0x73c8:jiā # 珈 0x73c9:mín # 珉 0x73ca:shān # 珊 0x73cb:liǔ # 珋 0x73cc:bì # 珌 0x73cd:zhēn # 珍 0x73ce:zhēn # 珎 0x73cf:jué # 珏 0x73d0:fà # 珐 0x73d1:lóng # 珑 0x73d2:jīn # 珒 0x73d3:jiào # 珓 0x73d4:jiàn # 珔 0x73d5:lì # 珕 0x73d6:guāng # 珖 0x73d7:xiān # 珗 0x73d8:zhōu # 珘 0x73d9:gǒng # 珙 0x73da:yān # 珚 0x73db:xiù # 珛 0x73dc:yáng # 珜 0x73dd:xǔ # 珝 0x73de:luò # 珞 0x73df:sù # 珟 0x73e0:zhū # 珠 0x73e1:qín # 珡 0x73e2:yín,kèn # 珢 0x73e3:xún # 珣 0x73e4:bǎo # 珤 0x73e5:ěr # 珥 0x73e6:xiàng # 珦 0x73e7:yáo # 珧 0x73e8:xiá # 珨 0x73e9:héng # 珩 0x73ea:guī # 珪 0x73eb:chōng # 珫 0x73ec:xù # 珬 0x73ed:bān # 班 0x73ee:pèi # 珮 0x73f0:dāng # 珰 0x73f2:hún,huī # 珲 0x73f3:wén # 珳 0x73f4:é # 珴 0x73f5:chéng # 珵 0x73f6:dì,tí # 珶 0x73f7:wǔ # 珷 0x73f8:wú # 珸 0x73f9:chéng # 珹 0x73fa:jùn # 珺 0x73fb:méi # 珻 0x73fc:bèi # 珼 0x73fd:tǐng # 珽 0x73fe:xiàn # 現 0x73ff:chù # 珿 0x7400:hán # 琀 0x7401:xuán,qióng # 琁 0x7402:yán # 琂 0x7403:qiú # 球 0x7404:xuàn # 琄 0x7405:láng # 琅 0x7406:lǐ # 理 0x7407:xiù # 琇 0x7408:fú,fū # 琈 0x7409:liú # 琉 0x740a:yá # 琊 0x740b:xī # 琋 0x740c:líng # 琌 0x740d:lí # 琍 0x740e:jīn # 琎 0x740f:liǎn # 琏 0x7410:suǒ # 琐 0x7413:wán # 琓 0x7414:diàn # 琔 0x7415:pín,bǐng # 琕 0x7416:zhǎn # 琖 0x7417:cuì,sè # 琗 0x7418:mín # 琘 0x7419:yù # 琙 0x741a:jū # 琚 0x741b:chēn # 琛 0x741c:lái # 琜 0x741d:mín # 琝 0x741e:shèng # 琞 0x741f:wéi,yù # 琟 0x7420:tiǎn,tiàn # 琠 0x7421:shū # 琡 0x7422:zhuó,zuó # 琢 0x7423:běng,pěi # 琣 0x7424:chēng # 琤 0x7425:hǔ # 琥 0x7426:qí # 琦 0x7427:è # 琧 0x7428:kūn # 琨 0x7429:chāng # 琩 0x742a:qí # 琪 0x742b:běng # 琫 0x742c:wǎn # 琬 0x742d:lù # 琭 0x742e:cóng # 琮 0x742f:guǎn # 琯 0x7430:yǎn # 琰 0x7431:diāo # 琱 0x7432:bèi # 琲 0x7433:lín # 琳 0x7434:qín # 琴 0x7435:pí # 琵 0x7436:pá # 琶 0x7437:què # 琷 0x7438:zhuó # 琸 0x7439:qín # 琹 0x743a:fà # 琺 0x743c:qióng # 琼 0x743d:dǔ # 琽 0x743e:jiè # 琾 0x743f:hún,huī # 琿 0x7440:yǔ # 瑀 0x7441:mào # 瑁 0x7442:méi # 瑂 0x7444:xuān # 瑄 0x7445:tí # 瑅 0x7446:xīng # 瑆 0x7447:dài # 瑇 0x7448:róu # 瑈 0x7449:mín # 瑉 0x744a:jiān # 瑊 0x744b:wěi # 瑋 0x744c:ruǎn # 瑌 0x744d:huàn # 瑍 0x744e:xié,jiē # 瑎 0x744f:chuān # 瑏 0x7450:jiǎn # 瑐 0x7451:zhuàn # 瑑 0x7452:chàng,yáng # 瑒 0x7453:liàn # 瑓 0x7454:quán # 瑔 0x7455:xiá # 瑕 0x7456:duàn # 瑖 0x7457:yuàn # 瑗 0x7458:yé # 瑘 0x7459:nǎo # 瑙 0x745a:hú # 瑚 0x745b:yīng # 瑛 0x745c:yú # 瑜 0x745d:huáng # 瑝 0x745e:ruì # 瑞 0x745f:sè # 瑟 0x7460:liú # 瑠 0x7462:róng # 瑢 0x7463:suǒ # 瑣 0x7464:yáo # 瑤 0x7465:wēn # 瑥 0x7466:wǔ # 瑦 0x7467:zhēn # 瑧 0x7468:jìn # 瑨 0x7469:yíng # 瑩 0x746a:mǎ # 瑪 0x746b:tāo # 瑫 0x746c:liú # 瑬 0x746d:táng # 瑭 0x746e:lì # 瑮 0x746f:láng # 瑯 0x7470:guī # 瑰 0x7471:tiàn,tián,zhèn # 瑱 0x7472:qiāng,cāng # 瑲 0x7473:cuō # 瑳 0x7474:jué # 瑴 0x7475:zhǎo # 瑵 0x7476:yáo # 瑶 0x7477:ài # 瑷 0x7478:bīn,pián # 瑸 0x7479:tú,shū # 瑹 0x747a:cháng # 瑺 0x747b:kūn # 瑻 0x747c:zhuān # 瑼 0x747d:cōng # 瑽 0x747e:jǐn # 瑾 0x747f:yī # 瑿 0x7480:cuǐ # 璀 0x7481:cōng # 璁 0x7482:qí # 璂 0x7483:lí # 璃 0x7484:jǐng # 璄 0x7485:zǎo,suǒ # 璅 0x7486:qiú # 璆 0x7487:xuán # 璇 0x7488:áo # 璈 0x7489:liǎn # 璉 0x748a:mén # 璊 0x748b:zhāng # 璋 0x748c:yín # 璌 0x748e:yīng # 璎 0x748f:zhì # 璏 0x7490:lù # 璐 0x7491:wú # 璑 0x7492:dēng # 璒 0x7494:zēng # 璔 0x7495:xún # 璕 0x7496:qú # 璖 0x7497:dàng # 璗 0x7498:lín # 璘 0x7499:liáo # 璙 0x749a:qióng,jué # 璚 0x749b:sù # 璛 0x749c:huáng # 璜 0x749d:guī # 璝 0x749e:pú # 璞 0x749f:jǐng # 璟 0x74a0:fán # 璠 0x74a1:jīn # 璡 0x74a2:liú # 璢 0x74a3:jī # 璣 0x74a5:jǐng # 璥 0x74a6:ài # 璦 0x74a7:bì # 璧 0x74a8:càn # 璨 0x74a9:qú # 璩 0x74aa:zǎo # 璪 0x74ab:dāng # 璫 0x74ac:jiǎo # 璬 0x74ad:guǎn # 璭 0x74ae:tǎn # 璮 0x74af:huì,kuài # 璯 0x74b0:huán # 環 0x74b1:sè # 璱 0x74b2:suì # 璲 0x74b3:tián # 璳 0x74b5:yú # 璵 0x74b6:jìn # 璶 0x74b7:lú,fū # 璷 0x74b8:bīn,pián # 璸 0x74b9:shú # 璹 0x74ba:wèn # 璺 0x74bb:zuǐ # 璻 0x74bc:lán # 璼 0x74bd:xǐ # 璽 0x74be:jì,zī # 璾 0x74bf:xuán # 璿 0x74c0:ruǎn # 瓀 0x74c1:wò # 瓁 0x74c2:gài # 瓂 0x74c3:léi # 瓃 0x74c4:dú # 瓄 0x74c5:lì # 瓅 0x74c6:zhì # 瓆 0x74c7:róu # 瓇 0x74c8:lí # 瓈 0x74c9:zàn # 瓉 0x74ca:qióng # 瓊 0x74cb:tì # 瓋 0x74cc:guī # 瓌 0x74cd:suí # 瓍 0x74ce:là # 瓎 0x74cf:lóng # 瓏 0x74d0:lú # 瓐 0x74d1:lì # 瓑 0x74d2:zàn # 瓒 0x74d3:làn # 瓓 0x74d4:yīng # 瓔 0x74d5:mí,xǐ # 瓕 0x74d6:xiāng # 瓖 0x74d7:qióng,wěi,wèi # 瓗 0x74d8:guàn # 瓘 0x74d9:dào # 瓙 0x74da:zàn # 瓚 0x74db:huán,yè,yà # 瓛 0x74dc:guā # 瓜 0x74dd:bó # 瓝 0x74de:dié # 瓞 0x74df:bó,páo # 瓟 0x74e0:hù # 瓠 0x74e1:zhí,hú # 瓡 0x74e2:piáo # 瓢 0x74e3:bàn # 瓣 0x74e4:ráng # 瓤 0x74e5:lì # 瓥 0x74e6:wǎ,wà # 瓦 0x74e8:xiáng,hóng # 瓨 0x74ea:bǎn # 瓪 0x74eb:pén # 瓫 0x74ec:fǎng # 瓬 0x74ed:dǎn # 瓭 0x74ee:wèng # 瓮 0x74ef:ōu # 瓯 0x74f3:hú # 瓳 0x74f4:líng # 瓴 0x74f5:yí # 瓵 0x74f6:píng # 瓶 0x74f7:cí # 瓷 0x74f9:juàn,juān # 瓹 0x74fa:cháng # 瓺 0x74fb:chī # 瓻 0x74fd:dàng # 瓽 0x74fe:wā # 瓾 0x74ff:bù # 瓿 0x7500:zhuì # 甀 0x7501:píng # 甁 0x7502:biān # 甂 0x7503:zhòu # 甃 0x7504:zhēn # 甄 0x7506:cí # 甆 0x7507:yīng # 甇 0x7508:qì # 甈 0x7509:xián # 甉 0x750a:lǒu # 甊 0x750b:dì # 甋 0x750c:ōu # 甌 0x750d:méng # 甍 0x750e:zhuān # 甎 0x750f:bèng # 甏 0x7510:lìn # 甐 0x7511:zèng # 甑 0x7512:wǔ # 甒 0x7513:pì # 甓 0x7514:dān # 甔 0x7515:wèng # 甕 0x7516:yīng # 甖 0x7517:yǎn # 甗 0x7518:gān # 甘 0x7519:dài # 甙 0x751a:shèn,shén # 甚 0x751b:tián # 甛 0x751c:tián # 甜 0x751d:hán # 甝 0x751e:cháng # 甞 0x751f:shēng # 生 0x7520:qíng # 甠 0x7521:shēn # 甡 0x7522:chǎn # 產 0x7523:chǎn # 産 0x7524:ruí # 甤 0x7525:shēng # 甥 0x7526:sū # 甦 0x7527:shēn # 甧 0x7528:yòng # 用 0x7529:shuǎi # 甩 0x752a:lù # 甪 0x752b:fǔ # 甫 0x752c:yǒng # 甬 0x752d:béng # 甭 0x752e:béng,fèng # 甮 0x752f:níng,nìng # 甯 0x7530:tián # 田 0x7531:yóu # 由 0x7532:jiǎ # 甲 0x7533:shēn # 申 0x7534:yóu,zhá # 甴 0x7535:diàn # 电 0x7536:fú # 甶 0x7537:nán # 男 0x7538:diàn,tián,shèng # 甸 0x7539:pīng # 甹 0x753a:tǐng,dīng # 町 0x753b:huà # 画 0x753c:tǐng,dīng # 甼 0x753d:zhèn # 甽 0x753e:zāi,zī # 甾 0x753f:méng # 甿 0x7540:bì # 畀 0x7541:bì,qí # 畁 0x7542:mǔ # 畂 0x7543:xún # 畃 0x7544:liú # 畄 0x7545:chàng # 畅 0x7546:mǔ # 畆 0x7547:yún # 畇 0x7548:fàn # 畈 0x7549:fú # 畉 0x754a:gēng # 畊 0x754b:tián # 畋 0x754c:jiè # 界 0x754d:jiè # 畍 0x754e:quǎn # 畎 0x754f:wèi # 畏 0x7550:fú,bì # 畐 0x7551:tián # 畑 0x7552:mǔ # 畒 0x7554:pàn # 畔 0x7555:jiāng # 畕 0x7556:wā # 畖 0x7557:dá,fú # 畗 0x7558:nán # 畘 0x7559:liú # 留 0x755a:běn # 畚 0x755b:zhěn # 畛 0x755c:xù,chù # 畜 0x755d:mǔ # 畝 0x755e:mǔ # 畞 0x755f:cè,jì # 畟 0x7561:gāi # 畡 0x7562:bì # 畢 0x7563:dá # 畣 0x7564:zhì,chóu,shì # 畤 0x7565:lüè # 略 0x7566:qí # 畦 0x7567:lüè # 畧 0x7568:fān,pān # 畨 0x756a:fān,pān # 番 0x756b:huà # 畫 0x756c:shē,yú # 畬 0x756d:shē # 畭 0x756e:mǔ # 畮 0x756f:jùn # 畯 0x7570:yì # 異 0x7571:liú # 畱 0x7572:shē # 畲 0x7573:dié # 畳 0x7574:chóu # 畴 0x7575:huà # 畵 0x7576:dāng,dàng,dǎng # 當 0x7577:zhuì # 畷 0x7578:jī # 畸 0x7579:wǎn # 畹 0x757a:jiāng,jiàng # 畺 0x757b:chéng # 畻 0x757c:chàng # 畼 0x757d:tuǎn # 畽 0x757e:léi # 畾 0x757f:jī # 畿 0x7580:chā # 疀 0x7581:liú # 疁 0x7583:tuǎn # 疃 0x7584:lín,lìn # 疄 0x7585:jiāng # 疅 0x7586:jiāng,qiáng # 疆 0x7587:chóu # 疇 0x7588:pì # 疈 0x7589:dié # 疉 0x758a:dié # 疊 0x758b:pǐ,yǎ,shū # 疋 0x758c:jié,qiè # 疌 0x758d:dàn # 疍 0x758e:shū # 疎 0x758f:shū # 疏 0x7590:zhì,dì # 疐 0x7591:yí,nǐ # 疑 0x7592:nè # 疒 0x7593:nǎi # 疓 0x7594:dīng # 疔 0x7595:bǐ # 疕 0x7596:jiē # 疖 0x7597:liáo # 疗 0x7598:gāng # 疘 0x7599:gē,yì # 疙 0x759a:jiù # 疚 0x759b:zhǒu # 疛 0x759c:xià # 疜 0x759d:shàn # 疝 0x759e:xū # 疞 0x759f:nüè,yào # 疟 0x75a0:lì,lài # 疠 0x75a1:yáng # 疡 0x75a2:chèn # 疢 0x75a3:yóu # 疣 0x75a4:bā # 疤 0x75a5:jiè # 疥 0x75a6:jué,xuè # 疦 0x75a7:qí # 疧 0x75a8:yǎ,xiā # 疨 0x75a9:cuì # 疩 0x75aa:bì # 疪 0x75ab:yì # 疫 0x75ac:lì # 疬 0x75ad:zòng # 疭 0x75ae:chuāng # 疮 0x75af:fēng # 疯 0x75b0:zhù # 疰 0x75b1:pào # 疱 0x75b2:pí # 疲 0x75b3:gān # 疳 0x75b4:kē # 疴 0x75b5:cī # 疵 0x75b6:xuē # 疶 0x75b7:zhī # 疷 0x75b8:dǎn,da # 疸 0x75b9:zhěn # 疹 0x75ba:fá,biǎn # 疺 0x75bb:zhǐ # 疻 0x75bc:téng # 疼 0x75bd:jū # 疽 0x75be:jí # 疾 0x75bf:fèi,féi # 疿 0x75c0:gōu # 痀 0x75c1:shān,diàn # 痁 0x75c2:jiā # 痂 0x75c3:xuán # 痃 0x75c4:zhà # 痄 0x75c5:bìng # 病 0x75c6:niè # 痆 0x75c7:zhèng,zhēng # 症 0x75c8:yōng # 痈 0x75c9:jìng # 痉 0x75ca:quán # 痊 0x75cb:téng,chóng # 痋 0x75cc:tōng,tóng # 痌 0x75cd:yí # 痍 0x75ce:jiē # 痎 0x75cf:wěi,yòu,yù # 痏 0x75d0:huí # 痐 0x75d1:tān,shǐ # 痑 0x75d2:yǎng # 痒 0x75d3:zhì,chì # 痓 0x75d4:zhì # 痔 0x75d5:hén # 痕 0x75d6:yǎ # 痖 0x75d7:mèi # 痗 0x75d8:dòu # 痘 0x75d9:jìng # 痙 0x75da:xiāo # 痚 0x75db:tòng # 痛 0x75dc:tū # 痜 0x75dd:máng # 痝 0x75de:pǐ # 痞 0x75df:xiāo # 痟 0x75e0:suān # 痠 0x75e1:pū,pù # 痡 0x75e2:lì # 痢 0x75e3:zhì # 痣 0x75e4:cuó # 痤 0x75e5:duó # 痥 0x75e6:wù # 痦 0x75e7:shā # 痧 0x75e8:láo # 痨 0x75e9:shòu # 痩 0x75ea:huàn # 痪 0x75eb:xián # 痫 0x75ec:yì # 痬 0x75ed:bēng,péng # 痭 0x75ee:zhàng # 痮 0x75ef:guǎn # 痯 0x75f0:tán # 痰 0x75f1:fèi,féi # 痱 0x75f2:má # 痲 0x75f3:má,lìn # 痳 0x75f4:chī # 痴 0x75f5:jì # 痵 0x75f6:tiǎn,diàn # 痶 0x75f7:ān,yè,è # 痷 0x75f8:chì # 痸 0x75f9:bì # 痹 0x75fa:bì # 痺 0x75fb:mín # 痻 0x75fc:gù # 痼 0x75fd:duī # 痽 0x75fe:kē,ē # 痾 0x75ff:wěi # 痿 0x7600:yū # 瘀 0x7601:cuì # 瘁 0x7602:yǎ # 瘂 0x7603:zhú # 瘃 0x7604:cù # 瘄 0x7605:dàn,dān # 瘅 0x7606:shèn # 瘆 0x7607:zhǒng # 瘇 0x7608:zhì,chì # 瘈 0x7609:yù # 瘉 0x760a:hóu # 瘊 0x760b:fēng # 瘋 0x760c:là # 瘌 0x760d:yáng # 瘍 0x760e:chén # 瘎 0x760f:tú # 瘏 0x7610:yǔ # 瘐 0x7611:guō # 瘑 0x7612:wén # 瘒 0x7613:huàn # 瘓 0x7614:kù # 瘔 0x7615:jiǎ,xiá,xiā # 瘕 0x7616:yīn # 瘖 0x7617:yì # 瘗 0x7618:lòu # 瘘 0x7619:sào # 瘙 0x761a:jué # 瘚 0x761b:chì # 瘛 0x761c:xī # 瘜 0x761d:guān # 瘝 0x761e:yì # 瘞 0x761f:wēn # 瘟 0x7620:jí # 瘠 0x7621:chuāng # 瘡 0x7622:bān # 瘢 0x7623:huì,lěi # 瘣 0x7624:liú # 瘤 0x7625:chài,cuó # 瘥 0x7626:shòu # 瘦 0x7627:nüè,yào # 瘧 0x7628:diān,chēn # 瘨 0x7629:dá,da # 瘩 0x762a:biē,biě # 瘪 0x762b:tān # 瘫 0x762c:zhàng # 瘬 0x762d:biāo # 瘭 0x762e:shèn # 瘮 0x762f:cù # 瘯 0x7630:luǒ # 瘰 0x7631:yì # 瘱 0x7632:zòng # 瘲 0x7633:chōu # 瘳 0x7634:zhàng # 瘴 0x7635:zhài # 瘵 0x7636:sòu # 瘶 0x7637:sè # 瘷 0x7638:qué # 瘸 0x7639:diào # 瘹 0x763a:lòu # 瘺 0x763b:lòu # 瘻 0x763c:mò # 瘼 0x763d:qín # 瘽 0x763e:yǐn # 瘾 0x763f:yǐng # 瘿 0x7640:huáng # 癀 0x7641:fú # 癁 0x7642:liáo # 療 0x7643:lóng # 癃 0x7644:qiáo,jiào # 癄 0x7645:liú # 癅 0x7646:láo # 癆 0x7647:xián # 癇 0x7648:fèi # 癈 0x7649:dàn,dān # 癉 0x764a:yìn # 癊 0x764b:hè # 癋 0x764c:ái # 癌 0x764d:bān # 癍 0x764e:xián # 癎 0x764f:guān # 癏 0x7650:guì,wēi # 癐 0x7651:nòng,nóng # 癑 0x7652:yù # 癒 0x7653:wēi # 癓 0x7654:yì # 癔 0x7655:yōng # 癕 0x7656:pǐ # 癖 0x7657:lěi # 癗 0x7658:lì,lài # 癘 0x7659:shǔ # 癙 0x765a:dàn # 癚 0x765b:lǐn # 癛 0x765c:diàn # 癜 0x765d:lǐn # 癝 0x765e:lài,là # 癞 0x765f:biē,biě # 癟 0x7660:jì # 癠 0x7661:chī # 癡 0x7662:yǎng # 癢 0x7663:xuǎn # 癣 0x7664:jiē # 癤 0x7665:zhēng # 癥 0x7667:lì # 癧 0x7668:huò # 癨 0x7669:lài # 癩 0x766b:diān # 癫 0x766c:xuǎn # 癬 0x766d:yǐng # 癭 0x766e:yǐn # 癮 0x766f:qú # 癯 0x7670:yōng # 癰 0x7671:tān # 癱 0x7672:diān # 癲 0x7673:luǒ # 癳 0x7674:luán # 癴 0x7675:luán # 癵 0x7676:bō # 癶 0x7678:guǐ # 癸 0x7679:bá # 癹 0x767a:fā # 発 0x767b:dēng # 登 0x767c:fā # 發 0x767d:bái # 白 0x767e:bǎi # 百 0x767f:qié # 癿 0x7680:jí,bī # 皀 0x7681:zào # 皁 0x7682:zào # 皂 0x7683:mào # 皃 0x7684:de,dí,dì # 的 0x7685:pā,bà # 皅 0x7686:jiē # 皆 0x7687:huáng # 皇 0x7688:guī # 皈 0x7689:cǐ # 皉 0x768a:líng # 皊 0x768b:gāo,háo # 皋 0x768c:mò # 皌 0x768d:jí # 皍 0x768e:jiǎo # 皎 0x768f:pěng # 皏 0x7690:gāo,yáo # 皐 0x7691:ái # 皑 0x7692:é # 皒 0x7693:hào # 皓 0x7694:hàn # 皔 0x7695:bì # 皕 0x7696:wǎn # 皖 0x7697:chóu # 皗 0x7698:qiàn # 皘 0x7699:xī # 皙 0x769a:ái # 皚 0x769b:xiǎo # 皛 0x769c:hào # 皜 0x769d:huàng # 皝 0x769e:hào # 皞 0x769f:zé # 皟 0x76a0:cuǐ # 皠 0x76a1:hào # 皡 0x76a2:xiǎo # 皢 0x76a3:yè # 皣 0x76a4:pó # 皤 0x76a5:hào # 皥 0x76a6:jiǎo # 皦 0x76a7:ài # 皧 0x76a8:xīng # 皨 0x76a9:huàng # 皩 0x76aa:lì,luò,bō # 皪 0x76ab:piǎo # 皫 0x76ac:hé # 皬 0x76ad:jiào # 皭 0x76ae:pí # 皮 0x76af:gǎn # 皯 0x76b0:pào # 皰 0x76b1:zhòu # 皱 0x76b2:jūn # 皲 0x76b3:qiú # 皳 0x76b4:cūn # 皴 0x76b5:què # 皵 0x76b6:zhā # 皶 0x76b7:gǔ # 皷 0x76b8:jūn # 皸 0x76b9:jūn # 皹 0x76ba:zhòu # 皺 0x76bb:zhā,cǔ # 皻 0x76bc:gǔ # 皼 0x76bd:zhāo,zhǎn,dǎn # 皽 0x76be:dú # 皾 0x76bf:mǐn # 皿 0x76c0:qǐ # 盀 0x76c1:yíng # 盁 0x76c2:yú # 盂 0x76c3:bēi # 盃 0x76c4:diào # 盄 0x76c5:zhōng # 盅 0x76c6:pén # 盆 0x76c7:hé # 盇 0x76c8:yíng # 盈 0x76c9:hé # 盉 0x76ca:yì # 益 0x76cb:bō # 盋 0x76cc:wǎn # 盌 0x76cd:hé # 盍 0x76ce:àng # 盎 0x76cf:zhǎn # 盏 0x76d0:yán # 盐 0x76d1:jiān,jiàn # 监 0x76d2:hé # 盒 0x76d3:yū # 盓 0x76d4:kuī # 盔 0x76d5:fàn # 盕 0x76d6:gài,gě,hé # 盖 0x76d7:dào # 盗 0x76d8:pán # 盘 0x76d9:fǔ # 盙 0x76da:qiú # 盚 0x76db:shèng,chéng # 盛 0x76dc:dào # 盜 0x76dd:lù # 盝 0x76de:zhǎn # 盞 0x76df:méng # 盟 0x76e0:lí # 盠 0x76e1:jìn # 盡 0x76e2:xù # 盢 0x76e3:jiān,jiàn # 監 0x76e4:pán # 盤 0x76e5:guàn # 盥 0x76e6:ān # 盦 0x76e7:lú # 盧 0x76e8:xǔ # 盨 0x76e9:zhōu,chóu # 盩 0x76ea:dàng # 盪 0x76eb:ān # 盫 0x76ec:gǔ # 盬 0x76ed:lì # 盭 0x76ee:mù # 目 0x76ef:dīng # 盯 0x76f0:gàn # 盰 0x76f1:xū # 盱 0x76f2:máng # 盲 0x76f3:máng,wàng # 盳 0x76f4:zhí # 直 0x76f5:qì # 盵 0x76f6:yuǎn # 盶 0x76f7:xián,tián # 盷 0x76f8:xiāng,xiàng # 相 0x76f9:dǔn # 盹 0x76fa:xīn # 盺 0x76fb:xì,pǎn # 盻 0x76fc:pàn # 盼 0x76fd:fēng # 盽 0x76fe:dùn # 盾 0x76ff:mín # 盿 0x7700:míng # 眀 0x7701:shěng,xǐng # 省 0x7702:shì # 眂 0x7703:yún,hùn # 眃 0x7704:miǎn # 眄 0x7705:pān # 眅 0x7706:fǎng # 眆 0x7707:miǎo # 眇 0x7708:dān # 眈 0x7709:méi # 眉 0x770a:mào # 眊 0x770b:kàn,kān # 看 0x770c:xiàn # 県 0x770d:kōu # 眍 0x770e:shì # 眎 0x770f:yāng,yǎng,yìng # 眏 0x7710:zhēng # 眐 0x7711:yǎo,āo,ǎo # 眑 0x7712:shēn # 眒 0x7713:huò # 眓 0x7714:dà # 眔 0x7715:zhěn # 眕 0x7716:kuàng # 眖 0x7717:jū,xū,kōu # 眗 0x7718:shèn # 眘 0x7719:yí,chì # 眙 0x771a:shěng # 眚 0x771b:mèi # 眛 0x771c:mò,miè # 眜 0x771d:zhù # 眝 0x771e:zhēn # 眞 0x771f:zhēn # 真 0x7720:mián # 眠 0x7721:shì # 眡 0x7722:yuān # 眢 0x7723:dié,tì # 眣 0x7724:nì # 眤 0x7725:zì # 眥 0x7726:zì # 眦 0x7727:chǎo # 眧 0x7728:zhǎ # 眨 0x7729:xuàn # 眩 0x772a:bǐng,fǎng # 眪 0x772b:pàng,pán # 眫 0x772c:lóng # 眬 0x772d:guì,suī # 眭 0x772e:tóng # 眮 0x772f:mī,mí # 眯 0x7730:dié,zhì # 眰 0x7731:dì # 眱 0x7732:nè # 眲 0x7733:míng # 眳 0x7734:xuàn,shùn,xún # 眴 0x7735:chī # 眵 0x7736:kuàng # 眶 0x7737:juàn # 眷 0x7738:móu # 眸 0x7739:zhèn # 眹 0x773a:tiào # 眺 0x773b:yáng # 眻 0x773c:yǎn # 眼 0x773d:mò # 眽 0x773e:zhòng # 眾 0x773f:mò # 眿 0x7740:zhe,zhuó,zháo,zhāo # 着 0x7741:zhēng # 睁 0x7742:méi # 睂 0x7743:suō # 睃 0x7744:qiáo,shào,xiāo # 睄 0x7745:hàn # 睅 0x7746:huǎn # 睆 0x7747:dì # 睇 0x7748:chěng # 睈 0x7749:cuó,zhuài # 睉 0x774a:juàn # 睊 0x774b:é # 睋 0x774c:miǎn # 睌 0x774d:xiàn # 睍 0x774e:xī # 睎 0x774f:kùn # 睏 0x7750:lài # 睐 0x7751:jiǎn # 睑 0x7752:shǎn # 睒 0x7753:tiǎn # 睓 0x7754:gùn # 睔 0x7755:wān # 睕 0x7756:lèng # 睖 0x7757:shì # 睗 0x7758:qióng # 睘 0x7759:lì # 睙 0x775a:yá # 睚 0x775b:jīng # 睛 0x775c:zhēng # 睜 0x775d:lí # 睝 0x775e:lài # 睞 0x775f:suì,zuì # 睟 0x7760:juàn # 睠 0x7761:shuì # 睡 0x7762:huī,suī # 睢 0x7763:dū # 督 0x7764:bì # 睤 0x7765:bì,pì # 睥 0x7766:mù # 睦 0x7767:hūn # 睧 0x7768:nì # 睨 0x7769:lù # 睩 0x776a:yì,zé,gāo # 睪 0x776b:jié # 睫 0x776c:cǎi # 睬 0x776d:zhǒu # 睭 0x776e:yú # 睮 0x776f:hūn # 睯 0x7770:mà # 睰 0x7771:xià # 睱 0x7772:xǐng,xìng # 睲 0x7773:huī # 睳 0x7774:hùn # 睴 0x7776:chǔn # 睶 0x7777:jiān # 睷 0x7778:mèi # 睸 0x7779:dǔ # 睹 0x777a:hóu # 睺 0x777b:xuān # 睻 0x777c:tí # 睼 0x777d:kuí # 睽 0x777e:gāo # 睾 0x777f:ruì # 睿 0x7780:mào # 瞀 0x7781:xù # 瞁 0x7782:fá # 瞂 0x7783:wò # 瞃 0x7784:miáo # 瞄 0x7785:chǒu # 瞅 0x7786:guì,wèi,kuì # 瞆 0x7787:mī,mí # 瞇 0x7788:wěng # 瞈 0x7789:kòu,jì # 瞉 0x778a:dàng # 瞊 0x778b:chēn # 瞋 0x778c:kē # 瞌 0x778d:sǒu # 瞍 0x778e:xiā # 瞎 0x778f:qióng,huán # 瞏 0x7790:mò # 瞐 0x7791:míng # 瞑 0x7792:mán,mén # 瞒 0x7793:fèn # 瞓 0x7794:zé # 瞔 0x7795:zhàng # 瞕 0x7796:yì # 瞖 0x7797:diāo,dōu # 瞗 0x7798:kōu # 瞘 0x7799:mò # 瞙 0x779a:shùn # 瞚 0x779b:cōng # 瞛 0x779c:lóu,lǘ,lou # 瞜 0x779d:chī # 瞝 0x779e:mán,mén # 瞞 0x779f:piǎo # 瞟 0x77a0:chēng # 瞠 0x77a1:guī # 瞡 0x77a2:méng,měng # 瞢 0x77a4:rún,shùn # 瞤 0x77a5:piē # 瞥 0x77a6:xī # 瞦 0x77a7:qiáo # 瞧 0x77a8:pú # 瞨 0x77a9:zhǔ # 瞩 0x77aa:dèng # 瞪 0x77ab:shěn # 瞫 0x77ac:shùn # 瞬 0x77ad:liǎo,liào # 瞭 0x77ae:chè # 瞮 0x77af:xián,jiàn # 瞯 0x77b0:kàn # 瞰 0x77b1:yè # 瞱 0x77b2:xuè # 瞲 0x77b3:tóng # 瞳 0x77b4:wǔ,mí # 瞴 0x77b5:lín # 瞵 0x77b6:guì,kuì # 瞶 0x77b7:jiàn # 瞷 0x77b8:yè # 瞸 0x77b9:ài # 瞹 0x77ba:huì # 瞺 0x77bb:zhān # 瞻 0x77bc:jiǎn # 瞼 0x77bd:gǔ # 瞽 0x77be:zhào # 瞾 0x77bf:qú,jù # 瞿 0x77c0:wéi # 矀 0x77c1:chǒu # 矁 0x77c2:sào # 矂 0x77c3:nǐng,chēng # 矃 0x77c4:xūn # 矄 0x77c5:yào # 矅 0x77c6:huò,yuè # 矆 0x77c7:mēng # 矇 0x77c8:mián # 矈 0x77c9:pín # 矉 0x77ca:mián # 矊 0x77cb:lěi # 矋 0x77cc:kuàng,guō # 矌 0x77cd:jué # 矍 0x77ce:xuān # 矎 0x77cf:mián # 矏 0x77d0:huò # 矐 0x77d1:lú # 矑 0x77d2:méng,měng # 矒 0x77d3:lóng # 矓 0x77d4:guàn,quán # 矔 0x77d5:mǎn,mán # 矕 0x77d6:xǐ # 矖 0x77d7:chù # 矗 0x77d8:tǎng # 矘 0x77d9:kàn # 矙 0x77da:zhǔ # 矚 0x77db:máo # 矛 0x77dc:jīn,qín,guān # 矜 0x77dd:jīn,qín,guān # 矝 0x77de:yù,xù,jué # 矞 0x77df:shuò # 矟 0x77e0:zé # 矠 0x77e1:jué # 矡 0x77e2:shǐ # 矢 0x77e3:yǐ # 矣 0x77e4:shěn # 矤 0x77e5:zhī,zhì # 知 0x77e6:hóu,hòu # 矦 0x77e7:shěn # 矧 0x77e8:yǐng # 矨 0x77e9:jǔ # 矩 0x77ea:zhōu # 矪 0x77eb:jiǎo,jiáo # 矫 0x77ec:cuó # 矬 0x77ed:duǎn # 短 0x77ee:ǎi # 矮 0x77ef:jiǎo,jiáo # 矯 0x77f0:zēng # 矰 0x77f1:yuē # 矱 0x77f2:bà # 矲 0x77f3:shí,dàn # 石 0x77f4:dìng # 矴 0x77f5:qì # 矵 0x77f6:jī # 矶 0x77f7:zǐ # 矷 0x77f8:gān # 矸 0x77f9:wù # 矹 0x77fa:zhé # 矺 0x77fb:kū # 矻 0x77fc:gāng,qiāng,kòng # 矼 0x77fd:xī # 矽 0x77fe:fán # 矾 0x77ff:kuàng # 矿 0x7800:dàng # 砀 0x7801:mǎ # 码 0x7802:shā # 砂 0x7803:dān # 砃 0x7804:jué # 砄 0x7805:lì # 砅 0x7806:fū # 砆 0x7807:mín # 砇 0x7808:è # 砈 0x7809:xū,huā # 砉 0x780a:kāng # 砊 0x780b:zhǐ # 砋 0x780c:qì,qiè # 砌 0x780d:kǎn # 砍 0x780e:jiè # 砎 0x780f:pīn,bīn,fēn # 砏 0x7810:è # 砐 0x7811:yà # 砑 0x7812:pī # 砒 0x7813:zhé # 砓 0x7814:yán,yàn # 研 0x7815:suì # 砕 0x7816:zhuān # 砖 0x7817:chē # 砗 0x7818:dùn # 砘 0x7819:wǎ # 砙 0x781a:yàn # 砚 0x781c:fēng # 砜 0x781d:fǎ # 砝 0x781e:mò # 砞 0x781f:zhǎ # 砟 0x7820:jū # 砠 0x7821:yù # 砡 0x7822:kē,luǒ # 砢 0x7823:tuó # 砣 0x7824:tuó # 砤 0x7825:dǐ # 砥 0x7826:zhài # 砦 0x7827:zhēn # 砧 0x7828:ě # 砨 0x7829:fú,fèi # 砩 0x782a:mǔ # 砪 0x782b:zhù,zhǔ # 砫 0x782c:lì,lā,lá # 砬 0x782d:biān # 砭 0x782e:nǔ # 砮 0x782f:pīng # 砯 0x7830:pēng # 砰 0x7831:líng # 砱 0x7832:pào # 砲 0x7833:lè # 砳 0x7834:pò # 破 0x7835:bō # 砵 0x7836:pò # 砶 0x7837:shēn # 砷 0x7838:zá # 砸 0x7839:ài # 砹 0x783a:lì # 砺 0x783b:lóng # 砻 0x783c:tóng # 砼 0x783e:lì # 砾 0x7840:chǔ # 础 0x7841:kēng # 硁 0x7842:quán # 硂 0x7843:zhū # 硃 0x7844:kuāng,guāng # 硄 0x7845:guī # 硅 0x7846:è # 硆 0x7847:náo # 硇 0x7848:qià # 硈 0x7849:lù # 硉 0x784a:wěi,guì # 硊 0x784b:ài # 硋 0x784c:luò,gè # 硌 0x784d:kèn,xiàn,gǔn,yǐn # 硍 0x784e:xíng # 硎 0x784f:yán,yàn # 硏 0x7850:dòng # 硐 0x7851:pēng,píng # 硑 0x7852:xī # 硒 0x7854:hóng # 硔 0x7855:shuò,shí # 硕 0x7856:xiá # 硖 0x7857:qiāo # 硗 0x7859:wéi,wèi,ái,gài # 硙 0x785a:qiáo # 硚 0x785c:kēng # 硜 0x785d:xiāo # 硝 0x785e:què,kè,kù # 硞 0x785f:chàn # 硟 0x7860:láng # 硠 0x7861:hōng # 硡 0x7862:yù # 硢 0x7863:xiāo # 硣 0x7864:xiá # 硤 0x7865:mǎng,bàng # 硥 0x7866:luò,lòng # 硦 0x7867:yǒng,tóng # 硧 0x7868:chē # 硨 0x7869:chè # 硩 0x786a:wò # 硪 0x786b:liú # 硫 0x786c:yìng # 硬 0x786d:máng # 硭 0x786e:què # 确 0x786f:yàn # 硯 0x7870:shā # 硰 0x7871:kǔn # 硱 0x7872:yù # 硲 0x7875:lǔ # 硵 0x7876:chěn # 硶 0x7877:jiǎn # 硷 0x7878:nüè # 硸 0x7879:sōng # 硹 0x787a:zhuó # 硺 0x787b:kēng,kěng # 硻 0x787c:péng # 硼 0x787d:yān,yǎn # 硽 0x787e:zhuì,chuí,duǒ # 硾 0x787f:kōng # 硿 0x7880:chēng # 碀 0x7881:qí # 碁 0x7882:zòng,cóng # 碂 0x7883:qìng # 碃 0x7884:lín # 碄 0x7885:jūn # 碅 0x7886:bō # 碆 0x7887:dìng # 碇 0x7888:mín # 碈 0x7889:diāo # 碉 0x788a:jiān,zhàn # 碊 0x788b:hè # 碋 0x788c:lù,liù # 碌 0x788d:ài # 碍 0x788e:suì # 碎 0x788f:què,xī # 碏 0x7890:léng # 碐 0x7891:bēi # 碑 0x7892:yín # 碒 0x7893:duì # 碓 0x7894:wǔ # 碔 0x7895:qí # 碕 0x7896:lún,lǔn,lùn # 碖 0x7897:wǎn # 碗 0x7898:diǎn # 碘 0x7899:náo,gāng # 碙 0x789a:bèi # 碚 0x789b:qì # 碛 0x789c:chěn # 碜 0x789d:ruǎn # 碝 0x789e:yán # 碞 0x789f:dié # 碟 0x78a0:dìng # 碠 0x78a1:zhóu # 碡 0x78a2:tuó # 碢 0x78a3:jié,yà # 碣 0x78a4:yīng # 碤 0x78a5:biǎn # 碥 0x78a6:kè # 碦 0x78a7:bì # 碧 0x78a8:wěi,wèi # 碨 0x78a9:shuò,shí # 碩 0x78aa:zhēn # 碪 0x78ab:duàn # 碫 0x78ac:xiá # 碬 0x78ad:dàng # 碭 0x78ae:tí,dī # 碮 0x78af:nǎo # 碯 0x78b0:pèng # 碰 0x78b1:jiǎn # 碱 0x78b2:dì # 碲 0x78b3:tàn # 碳 0x78b4:chá,chā # 碴 0x78b6:qì # 碶 0x78b8:fēng # 碸 0x78b9:xuàn # 碹 0x78ba:què # 確 0x78bb:què,qiāo # 碻 0x78bc:mǎ # 碼 0x78bd:gōng # 碽 0x78be:niǎn # 碾 0x78bf:sù,xiè # 碿 0x78c0:é # 磀 0x78c1:cí # 磁 0x78c2:liú,liù # 磂 0x78c3:sī,tí # 磃 0x78c4:táng # 磄 0x78c5:bàng,páng # 磅 0x78c6:huá,kě,gū # 磆 0x78c7:pī # 磇 0x78c8:kuǐ,wěi # 磈 0x78c9:sǎng # 磉 0x78ca:lěi # 磊 0x78cb:cuō # 磋 0x78cc:tián # 磌 0x78cd:xiá,qià,yà # 磍 0x78ce:xī # 磎 0x78cf:lián,qiān # 磏 0x78d0:pán # 磐 0x78d1:ái,wèi # 磑 0x78d2:yǔn # 磒 0x78d3:duī # 磓 0x78d4:zhé # 磔 0x78d5:kē # 磕 0x78d6:lá,lā # 磖 0x78d8:yáo # 磘 0x78d9:gǔn # 磙 0x78da:zhuān # 磚 0x78db:chán # 磛 0x78dc:qì # 磜 0x78dd:áo,qiāo # 磝 0x78de:pēng,pèng # 磞 0x78df:liù # 磟 0x78e0:lǔ # 磠 0x78e1:kàn # 磡 0x78e2:chuǎng # 磢 0x78e3:chěn # 磣 0x78e4:yīn,yǐn # 磤 0x78e5:lěi,léi # 磥 0x78e6:biāo # 磦 0x78e7:qì # 磧 0x78e8:mó,mò # 磨 0x78e9:qì,zhú # 磩 0x78ea:cuī # 磪 0x78eb:zōng # 磫 0x78ec:qìng # 磬 0x78ed:chuò # 磭 0x78ef:jī # 磯 0x78f0:shàn # 磰 0x78f1:láo,luò # 磱 0x78f2:qú # 磲 0x78f3:zēng # 磳 0x78f4:dèng # 磴 0x78f5:jiàn # 磵 0x78f6:xì # 磶 0x78f7:lín # 磷 0x78f8:dìng # 磸 0x78f9:diàn # 磹 0x78fa:huáng # 磺 0x78fb:pán,bō # 磻 0x78fc:jí,shé # 磼 0x78fd:qiāo # 磽 0x78fe:dī # 磾 0x78ff:lì # 磿 0x7901:jiāo # 礁 0x7903:zhǎng # 礃 0x7904:qiáo # 礄 0x7905:dūn # 礅 0x7906:jiǎn # 礆 0x7907:yù # 礇 0x7908:zhuì # 礈 0x7909:hé,qiāo,qiào # 礉 0x790a:kè,huò # 礊 0x790b:zé # 礋 0x790c:léi,lěi # 礌 0x790d:jié # 礍 0x790e:chǔ # 礎 0x790f:yè # 礏 0x7910:què,hú # 礐 0x7911:dàng # 礑 0x7912:yǐ # 礒 0x7913:jiāng # 礓 0x7914:pī # 礔 0x7915:pī # 礕 0x7916:yù # 礖 0x7917:pīn # 礗 0x7918:è,qì # 礘 0x7919:ài # 礙 0x791a:kē # 礚 0x791b:jiān # 礛 0x791c:yù # 礜 0x791d:ruǎn # 礝 0x791e:méng # 礞 0x791f:pào # 礟 0x7920:cí # 礠 0x7921:bō # 礡 0x7923:miè # 礣 0x7924:cǎ # 礤 0x7925:xián,xín # 礥 0x7926:kuàng # 礦 0x7927:léi,lěi,lèi # 礧 0x7928:lěi # 礨 0x7929:zhì # 礩 0x792a:lì # 礪 0x792b:lì # 礫 0x792c:fán # 礬 0x792d:què # 礭 0x792e:pào # 礮 0x792f:yīng # 礯 0x7930:lì # 礰 0x7931:lóng # 礱 0x7932:lóng # 礲 0x7933:mò # 礳 0x7934:bó # 礴 0x7935:shuāng # 礵 0x7936:guàn # 礶 0x7937:jiān # 礷 0x7938:cǎ # 礸 0x7939:yán,yǎn # 礹 0x793a:shì # 示 0x793b:shì # 礻 0x793c:lǐ # 礼 0x793d:réng # 礽 0x793e:shè # 社 0x793f:yuè # 礿 0x7940:sì # 祀 0x7941:qí # 祁 0x7942:tā # 祂 0x7943:mà # 祃 0x7944:xiè # 祄 0x7945:yāo # 祅 0x7946:xiān # 祆 0x7947:zhǐ,qí # 祇 0x7948:qí # 祈 0x7949:zhǐ # 祉 0x794a:bēng,fāng # 祊 0x794b:duì # 祋 0x794c:zhòng # 祌 0x794e:yī # 祎 0x794f:shí # 祏 0x7950:yòu # 祐 0x7951:zhì # 祑 0x7952:tiáo # 祒 0x7953:fú # 祓 0x7954:fù # 祔 0x7955:mì,bì # 祕 0x7956:zǔ # 祖 0x7957:zhī # 祗 0x7958:suàn # 祘 0x7959:mèi # 祙 0x795a:zuò # 祚 0x795b:qū # 祛 0x795c:hù # 祜 0x795d:zhù # 祝 0x795e:shén # 神 0x795f:suì # 祟 0x7960:cí # 祠 0x7961:chái # 祡 0x7962:mí # 祢 0x7963:lǚ # 祣 0x7964:yǔ # 祤 0x7965:xiáng # 祥 0x7966:wú # 祦 0x7967:tiāo # 祧 0x7968:piào,piāo # 票 0x7969:zhù # 祩 0x796a:guǐ # 祪 0x796b:xiá # 祫 0x796c:zhī # 祬 0x796d:jì,zhài # 祭 0x796e:gào # 祮 0x796f:zhēn # 祯 0x7970:gào # 祰 0x7971:shuì,lèi # 祱 0x7972:jìn # 祲 0x7973:shèn # 祳 0x7974:gāi # 祴 0x7975:kǔn # 祵 0x7976:dì # 祶 0x7977:dǎo # 祷 0x7978:huò # 祸 0x7979:táo # 祹 0x797a:qí # 祺 0x797b:gù # 祻 0x797c:guàn # 祼 0x797d:zuì # 祽 0x797e:líng # 祾 0x797f:lù # 祿 0x7980:bǐng # 禀 0x7981:jīn,jìn # 禁 0x7982:dǎo # 禂 0x7983:zhí # 禃 0x7984:lù # 禄 0x7985:chán,shàn # 禅 0x7986:bì,pí # 禆 0x7987:chǔ # 禇 0x7988:huī # 禈 0x7989:yǒu # 禉 0x798a:xì # 禊 0x798b:yīn # 禋 0x798c:zī # 禌 0x798d:huò # 禍 0x798e:zhēn # 禎 0x798f:fú # 福 0x7990:yuàn # 禐 0x7991:xú # 禑 0x7992:xiǎn # 禒 0x7993:shāng,yáng # 禓 0x7994:tí,zhǐ # 禔 0x7995:yī # 禕 0x7996:méi # 禖 0x7997:sī # 禗 0x7998:dì # 禘 0x799a:zhuó # 禚 0x799b:zhēn # 禛 0x799c:yíng # 禜 0x799d:jì # 禝 0x799e:gào # 禞 0x799f:táng # 禟 0x79a0:sī # 禠 0x79a1:mà # 禡 0x79a2:tà # 禢 0x79a4:xuān # 禤 0x79a5:qí # 禥 0x79a6:yù # 禦 0x79a7:xǐ # 禧 0x79a8:jī,jì # 禨 0x79a9:sì # 禩 0x79aa:shàn,chán # 禪 0x79ab:dàn # 禫 0x79ac:guì # 禬 0x79ad:suì # 禭 0x79ae:lǐ # 禮 0x79af:nóng # 禯 0x79b0:mí # 禰 0x79b1:dǎo # 禱 0x79b2:lì # 禲 0x79b3:ráng # 禳 0x79b4:yuè # 禴 0x79b5:tí # 禵 0x79b6:zàn # 禶 0x79b7:lèi # 禷 0x79b8:róu # 禸 0x79b9:yǔ # 禹 0x79ba:yú,yù,ǒu # 禺 0x79bb:lí # 离 0x79bc:xiè # 禼 0x79bd:qín # 禽 0x79be:hé # 禾 0x79bf:tū # 禿 0x79c0:xiù # 秀 0x79c1:sī # 私 0x79c2:rén # 秂 0x79c3:tū # 秃 0x79c4:zǐ,zì # 秄 0x79c5:chá,ná # 秅 0x79c6:gǎn # 秆 0x79c7:yì,zhí # 秇 0x79c8:xiān # 秈 0x79c9:bǐng # 秉 0x79ca:nián # 秊 0x79cb:qiū # 秋 0x79cc:qiū # 秌 0x79cd:zhǒng,zhòng,chóng # 种 0x79ce:fèn # 秎 0x79cf:hào,mào # 秏 0x79d0:yún # 秐 0x79d1:kē # 科 0x79d2:miǎo # 秒 0x79d3:zhī # 秓 0x79d4:jīng # 秔 0x79d5:bǐ # 秕 0x79d6:zhǐ # 秖 0x79d7:yù # 秗 0x79d8:mì,bì # 秘 0x79d9:kù,kū # 秙 0x79da:bàn # 秚 0x79db:pī # 秛 0x79dc:ní,nì # 秜 0x79dd:lì # 秝 0x79de:yóu # 秞 0x79df:zū # 租 0x79e0:pī # 秠 0x79e1:bó # 秡 0x79e2:líng # 秢 0x79e3:mò # 秣 0x79e4:chèng # 秤 0x79e5:nián # 秥 0x79e6:qín # 秦 0x79e7:yāng # 秧 0x79e8:zuó # 秨 0x79e9:zhì # 秩 0x79ea:dī # 秪 0x79eb:shú # 秫 0x79ec:jù # 秬 0x79ed:zǐ # 秭 0x79ee:huó,kuò # 秮 0x79ef:jī # 积 0x79f0:chēng,chèn,chèng # 称 0x79f1:tóng # 秱 0x79f2:shì,zhì # 秲 0x79f3:huó,kuò # 秳 0x79f4:huō # 秴 0x79f5:yīn # 秵 0x79f6:zī # 秶 0x79f7:zhì # 秷 0x79f8:jiē # 秸 0x79f9:rěn # 秹 0x79fa:dù # 秺 0x79fb:yí # 移 0x79fc:zhū # 秼 0x79fd:huì # 秽 0x79fe:nóng # 秾 0x79ff:fù,pū # 秿 0x7a00:xī # 稀 0x7a01:gǎo # 稁 0x7a02:láng # 稂 0x7a03:fū # 稃 0x7a04:xùn,zè # 稄 0x7a05:shuì # 稅 0x7a06:lǚ # 稆 0x7a07:kǔn # 稇 0x7a08:gǎn # 稈 0x7a09:jīng # 稉 0x7a0a:tí # 稊 0x7a0b:chéng # 程 0x7a0c:tú,shǔ # 稌 0x7a0d:shāo,shào # 稍 0x7a0e:shuì # 税 0x7a0f:yà # 稏 0x7a10:lǔn # 稐 0x7a11:lù # 稑 0x7a12:gū # 稒 0x7a13:zuó # 稓 0x7a14:rěn # 稔 0x7a15:zhùn,zhǔn # 稕 0x7a16:bàng # 稖 0x7a17:bài # 稗 0x7a18:jī,qí # 稘 0x7a19:zhī # 稙 0x7a1a:zhì # 稚 0x7a1b:kǔn # 稛 0x7a1c:léng,lēng,líng # 稜 0x7a1d:péng # 稝 0x7a1e:kē # 稞 0x7a1f:bǐng # 稟 0x7a20:chóu # 稠 0x7a21:zuì,zú,sū # 稡 0x7a22:yù # 稢 0x7a23:sū # 稣 0x7a24:lüè # 稤 0x7a26:yī # 稦 0x7a27:xì,qiè # 稧 0x7a28:biǎn # 稨 0x7a29:jì # 稩 0x7a2a:fú # 稪 0x7a2b:pì,bì # 稫 0x7a2c:nuò # 稬 0x7a2d:jiē # 稭 0x7a2e:zhǒng,zhòng # 種 0x7a2f:zōng,zǒng # 稯 0x7a30:xǔ,xū # 稰 0x7a31:chēng,chèn,chèng # 稱 0x7a32:dào # 稲 0x7a33:wěn # 稳 0x7a34:xián,jiān,liàn # 稴 0x7a35:zī,jiū # 稵 0x7a36:yù # 稶 0x7a37:jì # 稷 0x7a38:xù # 稸 0x7a39:zhěn # 稹 0x7a3a:zhì # 稺 0x7a3b:dào # 稻 0x7a3c:jià # 稼 0x7a3d:jī,qǐ # 稽 0x7a3e:gǎo # 稾 0x7a3f:gǎo # 稿 0x7a40:gǔ # 穀 0x7a41:róng # 穁 0x7a42:suì # 穂 0x7a44:jì # 穄 0x7a45:kāng # 穅 0x7a46:mù # 穆 0x7a47:cǎn,shān,cēn # 穇 0x7a48:mén,méi # 穈 0x7a49:zhì # 穉 0x7a4a:jì # 穊 0x7a4b:lù # 穋 0x7a4c:sū # 穌 0x7a4d:jī # 積 0x7a4e:yǐng # 穎 0x7a4f:wěn # 穏 0x7a50:qiū # 穐 0x7a51:sè # 穑 0x7a53:yì # 穓 0x7a54:huáng # 穔 0x7a55:qiè # 穕 0x7a56:jǐ,jì # 穖 0x7a57:suì # 穗 0x7a58:xiāo,rào # 穘 0x7a59:pú # 穙 0x7a5a:jiāo # 穚 0x7a5b:zhuō,bó # 穛 0x7a5c:tóng,zhǒng # 穜 0x7a5e:lǔ # 穞 0x7a5f:suì # 穟 0x7a60:nóng # 穠 0x7a61:sè # 穡 0x7a62:huì # 穢 0x7a63:ráng # 穣 0x7a64:nuò # 穤 0x7a65:yǔ # 穥 0x7a67:jì # 穧 0x7a68:tuí # 穨 0x7a69:wěn # 穩 0x7a6a:chēng,chèn,chèng # 穪 0x7a6b:huò # 穫 0x7a6c:kuàng # 穬 0x7a6d:lǚ # 穭 0x7a6e:biāo,pāo # 穮 0x7a70:ráng # 穰 0x7a71:zhuō,jué # 穱 0x7a72:lí # 穲 0x7a73:cuán,zàn # 穳 0x7a74:xué # 穴 0x7a75:wā # 穵 0x7a76:jiū # 究 0x7a77:qióng # 穷 0x7a78:xī # 穸 0x7a79:qióng # 穹 0x7a7a:kōng,kòng,kǒng # 空 0x7a7b:yū,yǔ # 穻 0x7a7c:shēn # 穼 0x7a7d:jǐng # 穽 0x7a7e:yào # 穾 0x7a7f:chuān # 穿 0x7a80:zhūn # 窀 0x7a81:tū # 突 0x7a82:láo # 窂 0x7a83:qiè # 窃 0x7a84:zhǎi # 窄 0x7a85:yǎo # 窅 0x7a86:biǎn # 窆 0x7a87:báo # 窇 0x7a88:yǎo # 窈 0x7a89:bìng # 窉 0x7a8a:wā # 窊 0x7a8b:zhú,kū # 窋 0x7a8c:jiào,liáo,liù # 窌 0x7a8d:qiào # 窍 0x7a8e:diào # 窎 0x7a8f:wū # 窏 0x7a90:wā,guī # 窐 0x7a91:yáo # 窑 0x7a92:zhì # 窒 0x7a93:chuāng # 窓 0x7a94:yào # 窔 0x7a95:tiǎo,yáo # 窕 0x7a96:jiào # 窖 0x7a97:chuāng # 窗 0x7a98:jiǒng # 窘 0x7a99:xiāo # 窙 0x7a9a:chéng # 窚 0x7a9b:kòu # 窛 0x7a9c:cuàn # 窜 0x7a9d:wō # 窝 0x7a9e:dàn # 窞 0x7a9f:kū # 窟 0x7aa0:kē # 窠 0x7aa1:zhuó # 窡 0x7aa2:huò # 窢 0x7aa3:sū # 窣 0x7aa5:kuī # 窥 0x7aa6:dòu # 窦 0x7aa8:yìn,xūn # 窨 0x7aa9:wō # 窩 0x7aaa:wā # 窪 0x7aab:yà,yē # 窫 0x7aac:yú # 窬 0x7aad:jù # 窭 0x7aae:qióng # 窮 0x7aaf:yáo # 窯 0x7ab0:yáo # 窰 0x7ab1:tiǎo # 窱 0x7ab2:cháo # 窲 0x7ab3:yǔ # 窳 0x7ab4:tián,diān,yǎn # 窴 0x7ab5:diào # 窵 0x7ab6:jù # 窶 0x7ab7:liào # 窷 0x7ab8:xī # 窸 0x7ab9:wù # 窹 0x7aba:kuī # 窺 0x7abb:chuāng # 窻 0x7abc:chāo,kē # 窼 0x7abe:kuǎn,cuàn # 窾 0x7abf:lóng # 窿 0x7ac0:chēng,chèng # 竀 0x7ac1:cuì # 竁 0x7ac2:liáo # 竂 0x7ac3:zào # 竃 0x7ac4:cuàn # 竄 0x7ac5:qiào # 竅 0x7ac6:qióng # 竆 0x7ac7:dòu # 竇 0x7ac8:zào # 竈 0x7ac9:lǒng # 竉 0x7aca:qiè # 竊 0x7acb:lì # 立 0x7acc:chù # 竌 0x7ace:fù # 竎 0x7ad0:chù,qì # 竐 0x7ad1:hóng # 竑 0x7ad2:qí # 竒 0x7ad6:shù # 竖 0x7ad7:miào # 竗 0x7ad8:qǔ,kǒu # 竘 0x7ad9:zhàn # 站 0x7ada:zhù # 竚 0x7adb:líng # 竛 0x7adc:lóng # 竜 0x7add:bìng # 竝 0x7ade:jìng # 竞 0x7adf:jìng # 竟 0x7ae0:zhāng # 章 0x7ae2:sì # 竢 0x7ae3:jùn # 竣 0x7ae4:hóng # 竤 0x7ae5:tóng # 童 0x7ae6:sǒng # 竦 0x7ae7:jìng,zhěn # 竧 0x7ae8:diào # 竨 0x7ae9:yì # 竩 0x7aea:shù # 竪 0x7aeb:jìng # 竫 0x7aec:qǔ # 竬 0x7aed:jié # 竭 0x7aee:píng # 竮 0x7aef:duān # 端 0x7af0:lí # 竰 0x7af1:zhuǎn # 竱 0x7af2:céng,zēng # 竲 0x7af3:dēng # 竳 0x7af4:cūn # 竴 0x7af5:wāi # 竵 0x7af6:jìng # 競 0x7af7:kǎn,kàn # 竷 0x7af8:jìng # 竸 0x7af9:zhú # 竹 0x7afa:zhú,dǔ # 竺 0x7afb:lè,jīn # 竻 0x7afc:péng # 竼 0x7afd:yú # 竽 0x7afe:chí # 竾 0x7aff:gān # 竿 0x7b00:máng # 笀 0x7b01:zhú # 笁 0x7b03:dǔ # 笃 0x7b04:jī # 笄 0x7b05:jiǎo,jiào # 笅 0x7b06:bā # 笆 0x7b07:suàn # 笇 0x7b08:jí # 笈 0x7b09:qǐn # 笉 0x7b0a:zhào # 笊 0x7b0b:sǔn # 笋 0x7b0c:yá # 笌 0x7b0d:zhuì,ruì # 笍 0x7b0e:yuán # 笎 0x7b0f:hù # 笏 0x7b10:háng,hàng # 笐 0x7b11:xiào # 笑 0x7b12:cén,jìn,hán # 笒 0x7b13:pí,bì # 笓 0x7b14:bǐ # 笔 0x7b15:jiǎn # 笕 0x7b16:yǐ # 笖 0x7b17:dōng # 笗 0x7b18:shān # 笘 0x7b19:shēng # 笙 0x7b1a:dā,xiá,nà # 笚 0x7b1b:dí # 笛 0x7b1c:zhú # 笜 0x7b1d:nà # 笝 0x7b1e:chī # 笞 0x7b1f:gū # 笟 0x7b20:lì # 笠 0x7b21:qiè # 笡 0x7b22:mǐn # 笢 0x7b23:bāo # 笣 0x7b24:tiáo # 笤 0x7b25:sì # 笥 0x7b26:fú # 符 0x7b27:cè # 笧 0x7b28:bèn # 笨 0x7b29:fá # 笩 0x7b2a:dá # 笪 0x7b2b:zǐ # 笫 0x7b2c:dì # 第 0x7b2d:líng # 笭 0x7b2e:zuó,zé # 笮 0x7b2f:nú # 笯 0x7b30:fú,fèi # 笰 0x7b31:gǒu # 笱 0x7b32:fán # 笲 0x7b33:jiā # 笳 0x7b34:gě,gǎn # 笴 0x7b35:fàn # 笵 0x7b36:shǐ # 笶 0x7b37:mǎo # 笷 0x7b38:pǒ # 笸 0x7b3a:jiān # 笺 0x7b3b:qióng # 笻 0x7b3c:lóng,lǒng # 笼 0x7b3e:biān # 笾 0x7b3f:luò # 笿 0x7b40:guì # 筀 0x7b41:qū # 筁 0x7b42:chí # 筂 0x7b43:yīn # 筃 0x7b44:yào # 筄 0x7b45:xiǎn # 筅 0x7b46:bǐ # 筆 0x7b47:qióng # 筇 0x7b48:kuò # 筈 0x7b49:děng # 等 0x7b4a:jiǎo,jiào # 筊 0x7b4b:jīn # 筋 0x7b4c:quán # 筌 0x7b4d:sǔn # 筍 0x7b4e:rú # 筎 0x7b4f:fá # 筏 0x7b50:kuāng # 筐 0x7b51:zhù,zhú # 筑 0x7b52:tǒng # 筒 0x7b53:jī # 筓 0x7b54:dá,dā # 答 0x7b55:háng # 筕 0x7b56:cè # 策 0x7b57:zhòng # 筗 0x7b58:kòu # 筘 0x7b59:lái # 筙 0x7b5a:bì # 筚 0x7b5b:shāi # 筛 0x7b5c:dāng # 筜 0x7b5d:zhēng # 筝 0x7b5e:cè # 筞 0x7b5f:fū # 筟 0x7b60:yún,jūn # 筠 0x7b61:tú # 筡 0x7b62:pá # 筢 0x7b63:lí # 筣 0x7b64:láng,làng # 筤 0x7b65:jǔ # 筥 0x7b66:guǎn # 筦 0x7b67:jiǎn # 筧 0x7b68:hán # 筨 0x7b69:tǒng # 筩 0x7b6a:xiá # 筪 0x7b6b:zhì,zhǐ # 筫 0x7b6c:chéng # 筬 0x7b6d:suàn # 筭 0x7b6e:shì # 筮 0x7b6f:zhù # 筯 0x7b70:zuó # 筰 0x7b71:xiǎo # 筱 0x7b72:shāo # 筲 0x7b73:tíng # 筳 0x7b74:cè,jiā # 筴 0x7b75:yán # 筵 0x7b76:gào # 筶 0x7b77:kuài # 筷 0x7b78:gān # 筸 0x7b79:chóu # 筹 0x7b7b:gàng # 筻 0x7b7c:yún # 筼 0x7b7e:qiān # 签 0x7b7f:xiǎo # 筿 0x7b80:jiǎn # 简 0x7b81:póu,bù,fú,pú # 箁 0x7b82:lái # 箂 0x7b83:zōu # 箃 0x7b84:pái,bēi # 箄 0x7b85:bì # 箅 0x7b86:bì # 箆 0x7b87:gè # 箇 0x7b88:tái,chí # 箈 0x7b89:guǎi,dài # 箉 0x7b8a:yū # 箊 0x7b8b:jiān # 箋 0x7b8c:zhào,dào # 箌 0x7b8d:gū # 箍 0x7b8e:chí # 箎 0x7b8f:zhēng # 箏 0x7b90:qìng,jīng # 箐 0x7b91:shà # 箑 0x7b92:zhǒu # 箒 0x7b93:lù # 箓 0x7b94:bó # 箔 0x7b95:jī # 箕 0x7b96:lín,lǐn # 箖 0x7b97:suàn # 算 0x7b98:jùn,qūn # 箘 0x7b99:fú # 箙 0x7b9a:zhá # 箚 0x7b9b:gū # 箛 0x7b9c:kōng # 箜 0x7b9d:qián # 箝 0x7b9e:quān # 箞 0x7b9f:jùn # 箟 0x7ba0:chuí # 箠 0x7ba1:guǎn # 管 0x7ba2:wǎn,yuān # 箢 0x7ba3:cè # 箣 0x7ba4:zú # 箤 0x7ba5:pǒ # 箥 0x7ba6:zé # 箦 0x7ba7:qiè # 箧 0x7ba8:tuò # 箨 0x7ba9:luó # 箩 0x7baa:dān # 箪 0x7bab:xiāo # 箫 0x7bac:ruò # 箬 0x7bad:jiàn # 箭 0x7baf:biān # 箯 0x7bb0:sǔn # 箰 0x7bb1:xiāng # 箱 0x7bb2:xiǎn # 箲 0x7bb3:píng # 箳 0x7bb4:zhēn # 箴 0x7bb5:xīng # 箵 0x7bb6:hú # 箶 0x7bb7:shī,yí # 箷 0x7bb8:zhù # 箸 0x7bb9:yuē,yào,chuò # 箹 0x7bba:chūn # 箺 0x7bbb:lǜ # 箻 0x7bbc:wū # 箼 0x7bbd:dǒng # 箽 0x7bbe:shuò,xiāo,qiào # 箾 0x7bbf:jí # 箿 0x7bc0:jié # 節 0x7bc1:huáng # 篁 0x7bc2:xīng # 篂 0x7bc3:mèi # 篃 0x7bc4:fàn # 範 0x7bc5:chuán # 篅 0x7bc6:zhuàn # 篆 0x7bc7:piān # 篇 0x7bc8:fēng # 篈 0x7bc9:zhù,zhú # 築 0x7bca:hóng # 篊 0x7bcb:qiè # 篋 0x7bcc:hóu # 篌 0x7bcd:qiū # 篍 0x7bce:miǎo # 篎 0x7bcf:qiàn # 篏 0x7bd1:kuì # 篑 0x7bd3:lǒu # 篓 0x7bd4:yún # 篔 0x7bd5:hé # 篕 0x7bd6:táng # 篖 0x7bd7:yuè # 篗 0x7bd8:chōu # 篘 0x7bd9:gāo # 篙 0x7bda:fěi # 篚 0x7bdb:ruò # 篛 0x7bdc:zhēng # 篜 0x7bdd:gōu # 篝 0x7bde:niè # 篞 0x7bdf:qiàn # 篟 0x7be0:xiǎo # 篠 0x7be1:cuàn # 篡 0x7be2:gōng,gǎn,lǒng # 篢 0x7be3:péng,páng # 篣 0x7be4:dǔ # 篤 0x7be5:lì # 篥 0x7be6:bì # 篦 0x7be7:zhuó,huò # 篧 0x7be8:chú # 篨 0x7be9:shāi # 篩 0x7bea:chí # 篪 0x7beb:zhù # 篫 0x7bec:qiāng,cāng # 篬 0x7bed:lóng,lǒng # 篭 0x7bee:lán # 篮 0x7bef:jiǎn,jiān # 篯 0x7bf0:bù # 篰 0x7bf1:lí # 篱 0x7bf2:huì # 篲 0x7bf3:bì # 篳 0x7bf4:zhú,dí # 篴 0x7bf5:cōng # 篵 0x7bf6:yān # 篶 0x7bf7:péng # 篷 0x7bf8:cēn,zān,cǎn # 篸 0x7bf9:zhuàn,zuàn,suǎn # 篹 0x7bfa:pí # 篺 0x7bfb:piǎo,biāo # 篻 0x7bfc:dōu # 篼 0x7bfd:yù # 篽 0x7bfe:miè # 篾 0x7bff:tuán,zhuān # 篿 0x7c00:zé # 簀 0x7c01:shāi # 簁 0x7c02:guó,guì # 簂 0x7c03:yí # 簃 0x7c04:hù # 簄 0x7c05:chǎn # 簅 0x7c06:kòu # 簆 0x7c07:cù # 簇 0x7c08:píng # 簈 0x7c09:zào # 簉 0x7c0a:jī # 簊 0x7c0b:guǐ # 簋 0x7c0c:sù # 簌 0x7c0d:lǒu # 簍 0x7c0e:cè,jí # 簎 0x7c0f:lù # 簏 0x7c10:niǎn # 簐 0x7c11:suō # 簑 0x7c12:cuàn # 簒 0x7c14:suō # 簔 0x7c15:lè # 簕 0x7c16:duàn # 簖 0x7c18:xiāo # 簘 0x7c19:bó # 簙 0x7c1a:mì,miè # 簚 0x7c1b:shāi,sī # 簛 0x7c1c:dàng # 簜 0x7c1d:liáo # 簝 0x7c1e:dān # 簞 0x7c1f:diàn # 簟 0x7c20:fǔ # 簠 0x7c21:jiǎn # 簡 0x7c22:mǐn # 簢 0x7c23:kuì # 簣 0x7c24:dài # 簤 0x7c25:jiāo # 簥 0x7c26:dēng # 簦 0x7c27:huáng # 簧 0x7c28:sǔn,zhuàn # 簨 0x7c29:láo # 簩 0x7c2a:zān # 簪 0x7c2b:xiāo # 簫 0x7c2c:lù # 簬 0x7c2d:shì # 簭 0x7c2e:zān # 簮 0x7c30:pái # 簰 0x7c32:pái # 簲 0x7c33:gǎn,gàn # 簳 0x7c34:jù # 簴 0x7c35:lù # 簵 0x7c36:lù # 簶 0x7c37:yán # 簷 0x7c38:bò,bǒ # 簸 0x7c39:dāng # 簹 0x7c3a:sài # 簺 0x7c3b:zhuā # 簻 0x7c3c:gōu # 簼 0x7c3d:qiān # 簽 0x7c3e:lián # 簾 0x7c3f:bù,bó # 簿 0x7c40:zhòu # 籀 0x7c41:lài # 籁 0x7c43:lán # 籃 0x7c44:kuì # 籄 0x7c45:yú # 籅 0x7c46:yuè # 籆 0x7c47:háo # 籇 0x7c48:zhēn,jiān # 籈 0x7c49:tái # 籉 0x7c4a:tì # 籊 0x7c4b:niè # 籋 0x7c4c:chóu # 籌 0x7c4d:jí # 籍 0x7c50:téng # 籐 0x7c51:zhuàn # 籑 0x7c52:zhòu # 籒 0x7c53:fān,pān,biān # 籓 0x7c54:sǒu,shǔ # 籔 0x7c55:zhòu # 籕 0x7c57:zhuó # 籗 0x7c58:téng # 籘 0x7c59:lù # 籙 0x7c5a:lú # 籚 0x7c5b:jiǎn,jiān # 籛 0x7c5c:tuò # 籜 0x7c5d:yíng # 籝 0x7c5e:yù # 籞 0x7c5f:lài # 籟 0x7c60:lóng,lǒng # 籠 0x7c62:lián # 籢 0x7c63:lán # 籣 0x7c64:qiān # 籤 0x7c65:yuè # 籥 0x7c66:zhōng # 籦 0x7c67:qú # 籧 0x7c68:lián # 籨 0x7c69:biān # 籩 0x7c6a:duàn # 籪 0x7c6b:zuǎn # 籫 0x7c6c:lí # 籬 0x7c6d:shāi # 籭 0x7c6e:luó # 籮 0x7c6f:yíng # 籯 0x7c70:yuè # 籰 0x7c71:zhuó # 籱 0x7c72:yù # 籲 0x7c73:mǐ # 米 0x7c74:dí # 籴 0x7c75:fán # 籵 0x7c76:shēn # 籶 0x7c77:zhé # 籷 0x7c78:shēn # 籸 0x7c79:nǚ # 籹 0x7c7a:hé # 籺 0x7c7b:lèi # 类 0x7c7c:xiān # 籼 0x7c7d:zǐ # 籽 0x7c7e:ní # 籾 0x7c7f:cùn # 籿 0x7c81:qiān # 粁 0x7c83:bǐ # 粃 0x7c84:bǎn # 粄 0x7c85:wù # 粅 0x7c86:shā,chǎo # 粆 0x7c87:kāng,jīng # 粇 0x7c88:róu # 粈 0x7c89:fěn # 粉 0x7c8a:bì # 粊 0x7c8b:cuì # 粋 0x7c8d:zhé # 粍 0x7c8e:mǐ # 粎 0x7c91:bā # 粑 0x7c92:lì # 粒 0x7c93:gān # 粓 0x7c94:jù # 粔 0x7c95:pò # 粕 0x7c96:yù # 粖 0x7c97:cū # 粗 0x7c98:nián,zhān # 粘 0x7c99:zhòu # 粙 0x7c9a:chī # 粚 0x7c9b:sù # 粛 0x7c9c:tiào # 粜 0x7c9d:lì # 粝 0x7c9e:xī # 粞 0x7c9f:sù # 粟 0x7ca0:hóng # 粠 0x7ca1:tóng # 粡 0x7ca2:zī,cí # 粢 0x7ca3:cè,sè # 粣 0x7ca4:yuè # 粤 0x7ca5:zhōu,yù # 粥 0x7ca6:lín # 粦 0x7ca7:zhuāng # 粧 0x7ca8:bǎi # 粨 0x7caa:fèn # 粪 0x7cae:liáng # 粮 0x7caf:xiàn # 粯 0x7cb0:fū,fú # 粰 0x7cb1:liáng # 粱 0x7cb2:càn # 粲 0x7cb3:jīng # 粳 0x7cb4:lǐ # 粴 0x7cb5:yuè # 粵 0x7cb6:lù # 粶 0x7cb7:jú # 粷 0x7cb8:qí # 粸 0x7cb9:cuì # 粹 0x7cba:bài # 粺 0x7cbb:zhāng # 粻 0x7cbc:lín # 粼 0x7cbd:zòng # 粽 0x7cbe:jīng # 精 0x7cbf:guǒ # 粿 0x7cc1:sǎn,shēn # 糁 0x7cc2:shēn # 糂 0x7cc3:táng # 糃 0x7cc4:biān,biǎn # 糄 0x7cc5:róu # 糅 0x7cc6:miàn # 糆 0x7cc7:hóu # 糇 0x7cc8:xǔ # 糈 0x7cc9:zòng # 糉 0x7cca:hū,hú,hù # 糊 0x7ccb:jiàn # 糋 0x7ccc:zān # 糌 0x7ccd:cí # 糍 0x7cce:lí # 糎 0x7ccf:xiè # 糏 0x7cd0:fū # 糐 0x7cd1:nuò # 糑 0x7cd2:bèi # 糒 0x7cd3:gǔ,gòu # 糓 0x7cd4:xiǔ # 糔 0x7cd5:gāo # 糕 0x7cd6:táng # 糖 0x7cd7:qiǔ # 糗 0x7cd9:cāo # 糙 0x7cda:zhuāng # 糚 0x7cdb:táng # 糛 0x7cdc:mí,méi # 糜 0x7cdd:sǎn,shēn # 糝 0x7cde:fèn # 糞 0x7cdf:zāo # 糟 0x7ce0:kāng # 糠 0x7ce1:jiàng # 糡 0x7ce2:mó # 糢 0x7ce3:sǎn,shēn # 糣 0x7ce4:sǎn # 糤 0x7ce5:nuò # 糥 0x7ce6:xī # 糦 0x7ce7:liáng # 糧 0x7ce8:jiàng # 糨 0x7ce9:kuài # 糩 0x7cea:bó # 糪 0x7ceb:huán # 糫 0x7ced:zòng # 糭 0x7cee:xiàn # 糮 0x7cef:nuò # 糯 0x7cf0:tuán # 糰 0x7cf1:niè # 糱 0x7cf2:lì # 糲 0x7cf3:zuò # 糳 0x7cf4:dí # 糴 0x7cf5:niè # 糵 0x7cf6:tiào # 糶 0x7cf7:làn # 糷 0x7cf8:mì,sī # 糸 0x7cf9:sī # 糹 0x7cfa:jiū,jiǔ # 糺 0x7cfb:xì,jì # 系 0x7cfc:gōng # 糼 0x7cfd:zhēng,zhěng # 糽 0x7cfe:jiū # 糾 0x7cff:gōng # 糿 0x7d00:jì # 紀 0x7d01:chà,chǎ # 紁 0x7d02:zhòu # 紂 0x7d03:xún # 紃 0x7d04:yuē,yāo # 約 0x7d05:hóng,gōng # 紅 0x7d06:yū # 紆 0x7d07:hé,gē # 紇 0x7d08:wán # 紈 0x7d09:rèn # 紉 0x7d0a:wěn # 紊 0x7d0b:wén,wèn # 紋 0x7d0c:qiú # 紌 0x7d0d:nà # 納 0x7d0e:zī # 紎 0x7d0f:tǒu # 紏 0x7d10:niǔ # 紐 0x7d11:fóu # 紑 0x7d12:jì,jié,jiè # 紒 0x7d13:shū # 紓 0x7d14:chún # 純 0x7d15:pī,pí,bǐ # 紕 0x7d16:zhèn # 紖 0x7d17:shā # 紗 0x7d18:hóng # 紘 0x7d19:zhǐ # 紙 0x7d1a:jí # 級 0x7d1b:fēn # 紛 0x7d1c:yún # 紜 0x7d1d:rèn # 紝 0x7d1e:dǎn # 紞 0x7d1f:jīn,jìn # 紟 0x7d20:sù # 素 0x7d21:fǎng # 紡 0x7d22:suǒ # 索 0x7d23:cuì # 紣 0x7d24:jiǔ # 紤 0x7d25:zhā,zā # 紥 0x7d27:jǐn # 紧 0x7d28:fū,fù # 紨 0x7d29:zhì # 紩 0x7d2a:qī # 紪 0x7d2b:zǐ # 紫 0x7d2c:chōu,chóu # 紬 0x7d2d:hóng # 紭 0x7d2e:zhā,zā # 紮 0x7d2f:léi,lěi,lèi # 累 0x7d30:xì # 細 0x7d31:fú # 紱 0x7d32:xiè # 紲 0x7d33:shēn # 紳 0x7d34:bō,bì # 紴 0x7d35:zhù # 紵 0x7d36:qū,qǔ # 紶 0x7d37:líng # 紷 0x7d38:zhù # 紸 0x7d39:shào # 紹 0x7d3a:gàn # 紺 0x7d3b:yǎng # 紻 0x7d3c:fú # 紼 0x7d3d:tuó # 紽 0x7d3e:zhěn,tiǎn # 紾 0x7d3f:dài # 紿 0x7d40:chù # 絀 0x7d41:shī # 絁 0x7d42:zhōng # 終 0x7d43:xián # 絃 0x7d44:zǔ # 組 0x7d45:jiōng,jiǒng # 絅 0x7d46:bàn # 絆 0x7d47:qú # 絇 0x7d48:mò # 絈 0x7d49:shù # 絉 0x7d4a:zuì # 絊 0x7d4c:jīng # 経 0x7d4d:rèn # 絍 0x7d4e:háng # 絎 0x7d4f:xiè # 絏 0x7d50:jié,jiē # 結 0x7d51:zhū # 絑 0x7d52:chóu # 絒 0x7d53:guà,kuā # 絓 0x7d54:bǎi,mò # 絔 0x7d55:jué # 絕 0x7d56:kuàng # 絖 0x7d57:hú # 絗 0x7d58:cì # 絘 0x7d59:huán,gēng # 絙 0x7d5a:gēng # 絚 0x7d5b:tāo # 絛 0x7d5c:xié,jié # 絜 0x7d5d:kù # 絝 0x7d5e:jiǎo # 絞 0x7d5f:quán,shuān # 絟 0x7d60:gǎi,ǎi # 絠 0x7d61:luò,lào # 絡 0x7d62:xuàn # 絢 0x7d63:bēng,bīng,pēng # 絣 0x7d64:xiàn # 絤 0x7d65:fú # 絥 0x7d66:gěi,jǐ # 給 0x7d67:tōng,tóng,dòng # 絧 0x7d68:róng # 絨 0x7d69:tiào,diào,dào # 絩 0x7d6a:yīn # 絪 0x7d6b:lěi,lèi,léi # 絫 0x7d6c:xiè # 絬 0x7d6d:juàn # 絭 0x7d6e:xù # 絮 0x7d6f:gāi,hài # 絯 0x7d70:dié # 絰 0x7d71:tǒng # 統 0x7d72:sī # 絲 0x7d73:jiàng # 絳 0x7d74:xiáng # 絴 0x7d75:huì # 絵 0x7d76:jué # 絶 0x7d77:zhí # 絷 0x7d78:jiǎn # 絸 0x7d79:juàn # 絹 0x7d7a:chī,zhǐ # 絺 0x7d7b:miǎn,wèn,mán,wàn # 絻 0x7d7c:zhèn # 絼 0x7d7d:lǚ # 絽 0x7d7e:chéng # 絾 0x7d7f:qiú # 絿 0x7d80:shū # 綀 0x7d81:bǎng # 綁 0x7d82:tǒng # 綂 0x7d83:xiāo # 綃 0x7d84:huán,huàn,wàn # 綄 0x7d85:qīn,xiān # 綅 0x7d86:gěng # 綆 0x7d87:xū # 綇 0x7d88:tí,tì # 綈 0x7d89:xiù # 綉 0x7d8a:xié # 綊 0x7d8b:hóng # 綋 0x7d8c:xì # 綌 0x7d8d:fú # 綍 0x7d8e:tīng # 綎 0x7d8f:suí # 綏 0x7d90:duì # 綐 0x7d91:kǔn # 綑 0x7d92:fū # 綒 0x7d93:jīng # 經 0x7d94:hù # 綔 0x7d95:zhī # 綕 0x7d96:yán,xiàn # 綖 0x7d97:jiǒng # 綗 0x7d98:féng # 綘 0x7d99:jì # 継 0x7d9c:zōng,zèng # 綜 0x7d9d:lín,chēn # 綝 0x7d9e:duǒ # 綞 0x7d9f:lì,liè # 綟 0x7da0:lǜ # 綠 0x7da1:jīng # 綡 0x7da2:chóu # 綢 0x7da3:quǎn # 綣 0x7da4:shào # 綤 0x7da5:qí # 綥 0x7da6:qí # 綦 0x7da7:zhǔn,zhùn # 綧 0x7da8:jī,qí # 綨 0x7da9:wǎn # 綩 0x7daa:qiàn,qīng,zhēng # 綪 0x7dab:xiàn # 綫 0x7dac:shòu # 綬 0x7dad:wéi # 維 0x7dae:qìng,qǐ # 綮 0x7daf:táo # 綯 0x7db0:wǎn # 綰 0x7db1:gāng # 綱 0x7db2:wǎng # 網 0x7db3:bēng,běng,bèng # 綳 0x7db4:zhuì # 綴 0x7db5:cǎi # 綵 0x7db6:guǒ # 綶 0x7db7:cuì # 綷 0x7db8:lún,guān # 綸 0x7db9:liǔ # 綹 0x7dba:qǐ # 綺 0x7dbb:zhàn # 綻 0x7dbc:bì # 綼 0x7dbd:chuò,chāo # 綽 0x7dbe:líng # 綾 0x7dbf:mián # 綿 0x7dc0:qī # 緀 0x7dc1:jī # 緁 0x7dc2:tián,tǎn,chān # 緂 0x7dc3:zōng # 緃 0x7dc4:gǔn # 緄 0x7dc5:zōu # 緅 0x7dc6:xī # 緆 0x7dc7:zī # 緇 0x7dc8:xìng # 緈 0x7dc9:liǎng # 緉 0x7dca:jǐn # 緊 0x7dcb:fēi # 緋 0x7dcc:ruí # 緌 0x7dcd:mín # 緍 0x7dce:yù # 緎 0x7dcf:zǒng # 総 0x7dd0:fán # 緐 0x7dd1:lǜ,lù # 緑 0x7dd2:xù # 緒 0x7dd3:yīng # 緓 0x7dd4:shàng # 緔 0x7dd6:xù # 緖 0x7dd7:xiāng # 緗 0x7dd8:jiān # 緘 0x7dd9:kè # 緙 0x7dda:xiàn # 線 0x7ddb:ruǎn,ruàn # 緛 0x7ddc:mián # 緜 0x7ddd:jī,qī # 緝 0x7dde:duàn # 緞 0x7ddf:chóng,zhòng # 緟 0x7de0:dì # 締 0x7de1:mín # 緡 0x7de2:miáo,máo # 緢 0x7de3:yuán # 緣 0x7de4:xiè,yè # 緤 0x7de5:bǎo # 緥 0x7de6:sī # 緦 0x7de7:qiū # 緧 0x7de8:biān # 編 0x7de9:huǎn # 緩 0x7dea:gēng,gèng # 緪 0x7deb:zǒng # 緫 0x7dec:miǎn # 緬 0x7ded:wèi # 緭 0x7dee:fù # 緮 0x7def:wěi # 緯 0x7df0:tōu,xū,shū # 緰 0x7df1:gōu # 緱 0x7df2:miǎo # 緲 0x7df3:xié # 緳 0x7df4:liàn # 練 0x7df5:zōng,zòng # 緵 0x7df6:biàn,pián # 緶 0x7df7:gǔn,yùn # 緷 0x7df8:yīn # 緸 0x7df9:tí # 緹 0x7dfa:guā,wō # 緺 0x7dfb:zhì # 緻 0x7dfc:yùn,yūn,wēn # 緼 0x7dfd:chēng # 緽 0x7dfe:chán # 緾 0x7dff:dài # 緿 0x7e00:xié # 縀 0x7e01:yuán # 縁 0x7e02:zǒng # 縂 0x7e03:xū # 縃 0x7e06:gēng,gèng # 縆 0x7e08:yíng # 縈 0x7e09:jìn # 縉 0x7e0a:yì # 縊 0x7e0b:zhuì # 縋 0x7e0c:nì # 縌 0x7e0d:bāng,bàng # 縍 0x7e0e:gǔ,hú # 縎 0x7e0f:pán # 縏 0x7e10:zhòu # 縐 0x7e11:jiān # 縑 0x7e12:cī,cuò,suǒ # 縒 0x7e13:quán # 縓 0x7e14:shuǎng # 縔 0x7e15:yùn,yūn,wēn # 縕 0x7e16:xiá # 縖 0x7e17:cuī,suī,shuāi # 縗 0x7e18:xì # 縘 0x7e19:róng,rǒng,ròng # 縙 0x7e1a:tāo # 縚 0x7e1b:fù # 縛 0x7e1c:yún # 縜 0x7e1d:zhěn # 縝 0x7e1e:gǎo # 縞 0x7e1f:rù # 縟 0x7e20:hú # 縠 0x7e21:zài,zēng # 縡 0x7e22:téng # 縢 0x7e23:xiàn,xuán # 縣 0x7e24:sù # 縤 0x7e25:zhěn # 縥 0x7e26:zòng # 縦 0x7e27:tāo # 縧 0x7e29:cài # 縩 0x7e2a:bì # 縪 0x7e2b:féng,fèng # 縫 0x7e2c:cù # 縬 0x7e2d:lí # 縭 0x7e2e:suō,sù # 縮 0x7e2f:yǎn,yǐn # 縯 0x7e30:xǐ # 縰 0x7e31:zòng,zǒng # 縱 0x7e32:léi # 縲 0x7e33:zhuàn,juàn # 縳 0x7e34:qiàn # 縴 0x7e35:màn # 縵 0x7e36:zhí # 縶 0x7e37:lǚ # 縷 0x7e38:mù,mò # 縸 0x7e39:piǎo,piāo # 縹 0x7e3a:lián # 縺 0x7e3b:mí # 縻 0x7e3c:xuàn # 縼 0x7e3d:zǒng # 總 0x7e3e:jì # 績 0x7e3f:shān # 縿 0x7e40:suì # 繀 0x7e41:fán,pó # 繁 0x7e42:lǜ # 繂 0x7e43:bēng,běng,bèng # 繃 0x7e44:yī # 繄 0x7e45:sāo # 繅 0x7e46:móu,miù,miào,mù,liǎo # 繆 0x7e47:yáo,yóu,zhòu # 繇 0x7e48:qiǎng # 繈 0x7e49:shéng,hún # 繉 0x7e4b:jì # 繋 0x7e4d:xiù # 繍 0x7e4e:rán # 繎 0x7e4f:xuàn # 繏 0x7e50:suì # 繐 0x7e51:qiāo # 繑 0x7e52:zēng,zèng # 繒 0x7e53:zuǒ # 繓 0x7e54:zhī,zhì # 織 0x7e55:shàn # 繕 0x7e56:sǎn # 繖 0x7e57:lín # 繗 0x7e58:jú,jué # 繘 0x7e59:fān # 繙 0x7e5a:liáo # 繚 0x7e5b:chuō,chuò # 繛 0x7e5c:zūn,zǔn # 繜 0x7e5d:jiàn # 繝 0x7e5e:rào # 繞 0x7e5f:chǎn,chán # 繟 0x7e60:ruǐ # 繠 0x7e61:xiù # 繡 0x7e62:huì,huí # 繢 0x7e63:huà # 繣 0x7e64:zuǎn # 繤 0x7e65:xī # 繥 0x7e66:qiǎng # 繦 0x7e68:da # 繨 0x7e69:shéng # 繩 0x7e6a:huì # 繪 0x7e6b:xì,jì # 繫 0x7e6c:sè # 繬 0x7e6d:jiǎn # 繭 0x7e6e:jiāng # 繮 0x7e6f:huán # 繯 0x7e70:qiāo,sāo # 繰 0x7e71:cōng # 繱 0x7e72:xiè # 繲 0x7e73:jiǎo,zhuó # 繳 0x7e74:bì # 繴 0x7e75:dàn,tán,chán # 繵 0x7e76:yì # 繶 0x7e77:nǒng # 繷 0x7e78:suì # 繸 0x7e79:yì # 繹 0x7e7a:shā # 繺 0x7e7b:rú,xū # 繻 0x7e7c:jì # 繼 0x7e7d:bīn # 繽 0x7e7e:qiǎn # 繾 0x7e7f:lán # 繿 0x7e80:pú,fú # 纀 0x7e81:xūn # 纁 0x7e82:zuǎn # 纂 0x7e83:zī # 纃 0x7e84:péng # 纄 0x7e85:yào,lì # 纅 0x7e86:mò # 纆 0x7e87:lèi # 纇 0x7e88:xiè # 纈 0x7e89:zuǎn # 纉 0x7e8a:kuàng # 纊 0x7e8b:yōu # 纋 0x7e8c:xù # 續 0x7e8d:léi # 纍 0x7e8e:xiān # 纎 0x7e8f:chán # 纏 0x7e91:lú # 纑 0x7e92:chán # 纒 0x7e93:yīng # 纓 0x7e94:cái # 纔 0x7e95:xiāng,rǎng # 纕 0x7e96:xiān # 纖 0x7e97:zuī # 纗 0x7e98:zuǎn # 纘 0x7e99:luò # 纙 0x7e9a:lí,xǐ,lǐ,sǎ # 纚 0x7e9b:dào # 纛 0x7e9c:lǎn # 纜 0x7e9d:léi # 纝 0x7e9e:liàn # 纞 0x7e9f:sī # 纟 0x7ea0:jiū # 纠 0x7ea1:yū # 纡 0x7ea2:hóng,gōng # 红 0x7ea3:zhòu # 纣 0x7ea4:xiān,qiàn # 纤 0x7ea5:hé,gē # 纥 0x7ea6:yuē,yāo # 约 0x7ea7:jí # 级 0x7ea8:wán # 纨 0x7ea9:kuàng # 纩 0x7eaa:jì,jǐ # 纪 0x7eab:rèn # 纫 0x7eac:wěi # 纬 0x7ead:yún # 纭 0x7eae:hóng # 纮 0x7eaf:chún # 纯 0x7eb0:pī,pí,bǐ # 纰 0x7eb1:shā # 纱 0x7eb2:gāng # 纲 0x7eb3:nà # 纳 0x7eb4:rèn # 纴 0x7eb5:zòng,zǒng # 纵 0x7eb6:lún,guān # 纶 0x7eb7:fēn # 纷 0x7eb8:zhǐ # 纸 0x7eb9:wén,wèn # 纹 0x7eba:fǎng # 纺 0x7ebb:zhù # 纻 0x7ebc:zhèn # 纼 0x7ebd:niǔ # 纽 0x7ebe:shū # 纾 0x7ebf:xiàn # 线 0x7ec0:gàn # 绀 0x7ec1:xiè # 绁 0x7ec2:fú # 绂 0x7ec3:liàn # 练 0x7ec4:zǔ # 组 0x7ec5:shēn # 绅 0x7ec6:xì # 细 0x7ec7:zhī,zhì # 织 0x7ec8:zhōng # 终 0x7ec9:zhòu # 绉 0x7eca:bàn # 绊 0x7ecb:fú # 绋 0x7ecc:chù # 绌 0x7ecd:shào # 绍 0x7ece:yì # 绎 0x7ecf:jīng # 经 0x7ed0:dài # 绐 0x7ed1:bǎng # 绑 0x7ed2:róng # 绒 0x7ed3:jié,jiē # 结 0x7ed4:kù # 绔 0x7ed5:rào # 绕 0x7ed6:dié # 绖 0x7ed7:háng # 绗 0x7ed8:huì # 绘 0x7ed9:gěi,jǐ # 给 0x7eda:xuàn # 绚 0x7edb:jiàng # 绛 0x7edc:luò,lào # 络 0x7edd:jué # 绝 0x7ede:jiǎo # 绞 0x7edf:tǒng # 统 0x7ee0:gěng # 绠 0x7ee1:xiāo # 绡 0x7ee2:juàn # 绢 0x7ee3:xiù # 绣 0x7ee4:xì # 绤 0x7ee5:suí # 绥 0x7ee6:tāo # 绦 0x7ee7:jì # 继 0x7ee8:tí,tì # 绨 0x7ee9:jì # 绩 0x7eea:xù # 绪 0x7eeb:líng # 绫 0x7eec:yīng # 绬 0x7eed:xù # 续 0x7eee:qǐ # 绮 0x7eef:fēi # 绯 0x7ef0:chuò,chāo # 绰 0x7ef1:shàng # 绱 0x7ef2:gǔn # 绲 0x7ef3:shéng # 绳 0x7ef4:wéi # 维 0x7ef5:mián # 绵 0x7ef6:shòu # 绶 0x7ef7:bēng,běng,bèng # 绷 0x7ef8:chóu # 绸 0x7ef9:táo # 绹 0x7efa:liǔ # 绺 0x7efb:quǎn # 绻 0x7efc:zōng,zèng # 综 0x7efd:zhàn # 绽 0x7efe:wǎn # 绾 0x7eff:lǜ,lù # 绿 0x7f00:zhuì # 缀 0x7f01:zī # 缁 0x7f02:kè # 缂 0x7f03:xiāng # 缃 0x7f04:jiān # 缄 0x7f05:miǎn # 缅 0x7f06:lǎn # 缆 0x7f07:tí # 缇 0x7f08:miǎo # 缈 0x7f09:jī,qī # 缉 0x7f0a:yùn,yūn,wēn # 缊 0x7f0b:huì,huí # 缋 0x7f0c:sī # 缌 0x7f0d:duǒ # 缍 0x7f0e:duàn # 缎 0x7f0f:biàn,pián # 缏 0x7f10:xiàn # 缐 0x7f11:gōu # 缑 0x7f12:zhuì # 缒 0x7f13:huǎn # 缓 0x7f14:dì # 缔 0x7f15:lǚ # 缕 0x7f16:biān # 编 0x7f17:mín # 缗 0x7f18:yuán # 缘 0x7f19:jìn # 缙 0x7f1a:fù # 缚 0x7f1b:rù # 缛 0x7f1c:zhěn # 缜 0x7f1d:féng,fèng # 缝 0x7f1e:cuī,suī,shuāi # 缞 0x7f1f:gǎo # 缟 0x7f20:chán # 缠 0x7f21:lí # 缡 0x7f22:yì # 缢 0x7f23:jiān # 缣 0x7f24:bīn # 缤 0x7f25:piǎo,piāo # 缥 0x7f26:màn # 缦 0x7f27:léi # 缧 0x7f28:yīng # 缨 0x7f29:suō,sù # 缩 0x7f2a:móu,miù,miào,mù,liǎo # 缪 0x7f2b:sāo # 缫 0x7f2c:xié # 缬 0x7f2d:liáo # 缭 0x7f2e:shàn # 缮 0x7f2f:zēng,zèng # 缯 0x7f30:jiāng # 缰 0x7f31:qiǎn # 缱 0x7f32:qiāo,sāo # 缲 0x7f33:huán # 缳 0x7f34:jiǎo,zhuó # 缴 0x7f35:zuǎn # 缵 0x7f36:fǒu # 缶 0x7f37:xiè # 缷 0x7f38:gāng # 缸 0x7f39:fǒu # 缹 0x7f3a:quē # 缺 0x7f3b:fǒu # 缻 0x7f3d:bō # 缽 0x7f3e:píng # 缾 0x7f3f:xiàng # 缿 0x7f41:gāng # 罁 0x7f42:yīng # 罂 0x7f43:yīng # 罃 0x7f44:qìng # 罄 0x7f45:xià # 罅 0x7f46:guàn # 罆 0x7f47:zūn # 罇 0x7f48:tán # 罈 0x7f4a:qì # 罊 0x7f4b:wèng # 罋 0x7f4c:yīng # 罌 0x7f4d:léi # 罍 0x7f4e:tán # 罎 0x7f4f:lú # 罏 0x7f50:guàn # 罐 0x7f51:wǎng # 网 0x7f52:wǎng # 罒 0x7f53:wǎng # 罓 0x7f54:wǎng # 罔 0x7f55:hǎn # 罕 0x7f57:luó # 罗 0x7f58:fú # 罘 0x7f59:shēn # 罙 0x7f5a:fá # 罚 0x7f5b:gū # 罛 0x7f5c:zhǔ # 罜 0x7f5d:jū # 罝 0x7f5e:máo # 罞 0x7f5f:gǔ # 罟 0x7f60:mín # 罠 0x7f61:gāng # 罡 0x7f62:bà,ba,pí # 罢 0x7f63:guà # 罣 0x7f64:tí # 罤 0x7f65:juàn # 罥 0x7f66:fú # 罦 0x7f67:shēn # 罧 0x7f68:yǎn # 罨 0x7f69:zhào # 罩 0x7f6a:zuì # 罪 0x7f6b:guǎi,guà # 罫 0x7f6c:zhuó # 罬 0x7f6d:yù # 罭 0x7f6e:zhì # 置 0x7f6f:ǎn # 罯 0x7f70:fá # 罰 0x7f71:lǎn # 罱 0x7f72:shǔ # 署 0x7f73:sī # 罳 0x7f74:pí # 罴 0x7f75:mà # 罵 0x7f76:liǔ # 罶 0x7f77:bà,ba,pí # 罷 0x7f78:fá # 罸 0x7f79:lí # 罹 0x7f7a:cháo # 罺 0x7f7b:wèi # 罻 0x7f7c:bì # 罼 0x7f7d:jì # 罽 0x7f7e:zēng # 罾 0x7f7f:chōng # 罿 0x7f80:liǔ # 羀 0x7f81:jī # 羁 0x7f82:juàn # 羂 0x7f83:mì # 羃 0x7f84:zhào # 羄 0x7f85:luó # 羅 0x7f86:pí # 羆 0x7f87:jī # 羇 0x7f88:jī # 羈 0x7f89:luán # 羉 0x7f8a:yáng,xiáng # 羊 0x7f8b:mǐ # 羋 0x7f8c:qiāng # 羌 0x7f8d:dá # 羍 0x7f8e:měi # 美 0x7f8f:yáng,xiáng # 羏 0x7f90:líng # 羐 0x7f91:yǒu # 羑 0x7f92:fén # 羒 0x7f93:bā # 羓 0x7f94:gāo # 羔 0x7f95:yàng # 羕 0x7f96:gǔ # 羖 0x7f97:qiāng # 羗 0x7f98:zāng # 羘 0x7f99:měi,gāo # 羙 0x7f9a:líng # 羚 0x7f9b:yì,xī # 羛 0x7f9c:zhù # 羜 0x7f9d:dī # 羝 0x7f9e:xiū # 羞 0x7f9f:qiǎng # 羟 0x7fa0:yí # 羠 0x7fa1:xiàn # 羡 0x7fa2:róng # 羢 0x7fa3:qún # 羣 0x7fa4:qún # 群 0x7fa5:qiǎng # 羥 0x7fa6:huán # 羦 0x7fa7:suō # 羧 0x7fa8:xiàn # 羨 0x7fa9:yì # 義 0x7fab:qiāng,kòng # 羫 0x7fac:qián,xián,yán # 羬 0x7fad:yú # 羭 0x7fae:gēng # 羮 0x7faf:jié # 羯 0x7fb0:tāng # 羰 0x7fb1:yuán # 羱 0x7fb2:xī # 羲 0x7fb3:fán # 羳 0x7fb4:shān # 羴 0x7fb5:fén # 羵 0x7fb6:shān # 羶 0x7fb7:liǎn # 羷 0x7fb8:léi # 羸 0x7fb9:gēng # 羹 0x7fba:nóu # 羺 0x7fbb:qiàng # 羻 0x7fbc:chàn # 羼 0x7fbd:yǔ # 羽 0x7fbe:hóng,gòng # 羾 0x7fbf:yì # 羿 0x7fc0:chōng # 翀 0x7fc1:wēng # 翁 0x7fc2:fēn # 翂 0x7fc3:hóng # 翃 0x7fc4:chì # 翄 0x7fc5:chì # 翅 0x7fc6:cuì # 翆 0x7fc7:fú # 翇 0x7fc8:xiá # 翈 0x7fc9:běn # 翉 0x7fca:yì # 翊 0x7fcb:là # 翋 0x7fcc:yì # 翌 0x7fcd:pī,bì,pō # 翍 0x7fce:líng # 翎 0x7fcf:liù # 翏 0x7fd0:zhì # 翐 0x7fd1:qú,yù # 翑 0x7fd2:xí # 習 0x7fd3:xié # 翓 0x7fd4:xiáng # 翔 0x7fd5:xī # 翕 0x7fd6:xī # 翖 0x7fd7:ké # 翗 0x7fd8:qiáo,qiào # 翘 0x7fd9:huì # 翙 0x7fda:huī # 翚 0x7fdb:xiāo # 翛 0x7fdc:shà # 翜 0x7fdd:hóng # 翝 0x7fde:jiāng # 翞 0x7fdf:dí,zhái # 翟 0x7fe0:cuì # 翠 0x7fe1:fěi # 翡 0x7fe2:dào,zhōu # 翢 0x7fe3:shà # 翣 0x7fe4:chì # 翤 0x7fe5:zhù # 翥 0x7fe6:jiǎn # 翦 0x7fe7:xuān # 翧 0x7fe8:chì # 翨 0x7fe9:piān # 翩 0x7fea:zōng # 翪 0x7feb:wán # 翫 0x7fec:huī # 翬 0x7fed:hóu # 翭 0x7fee:hé # 翮 0x7fef:hè # 翯 0x7ff0:hàn # 翰 0x7ff1:áo # 翱 0x7ff2:piāo # 翲 0x7ff3:yì # 翳 0x7ff4:lián # 翴 0x7ff5:hóu,qú # 翵 0x7ff7:lín # 翷 0x7ff8:pěn # 翸 0x7ff9:qiáo,qiào # 翹 0x7ffa:áo # 翺 0x7ffb:fān # 翻 0x7ffc:yì # 翼 0x7ffd:huì # 翽 0x7ffe:xuān # 翾 0x7fff:dào # 翿 0x8000:yào # 耀 0x8001:lǎo # 老 0x8003:kǎo # 考 0x8004:mào # 耄 0x8005:zhě # 者 0x8006:qí,shì # 耆 0x8007:gǒu # 耇 0x8008:gǒu # 耈 0x8009:gǒu # 耉 0x800a:dié # 耊 0x800b:dié # 耋 0x800c:ér # 而 0x800d:shuǎ # 耍 0x800e:ruǎn,nuò # 耎 0x800f:ér,nài # 耏 0x8010:nài # 耐 0x8011:duān,zhuān # 耑 0x8012:lěi # 耒 0x8013:tīng # 耓 0x8014:zǐ # 耔 0x8015:gēng # 耕 0x8016:chào # 耖 0x8017:hào # 耗 0x8018:yún # 耘 0x8019:bà,pá # 耙 0x801a:pī # 耚 0x801b:sì,chí # 耛 0x801c:sì # 耜 0x801d:qù,chú # 耝 0x801e:jiā # 耞 0x801f:jù # 耟 0x8020:huō # 耠 0x8021:chú # 耡 0x8022:lào # 耢 0x8023:lún,lǔn # 耣 0x8024:jí,jiè # 耤 0x8025:tǎng # 耥 0x8026:ǒu # 耦 0x8027:lóu # 耧 0x8028:nòu # 耨 0x8029:jiǎng # 耩 0x802a:pǎng # 耪 0x802b:zhá,zé # 耫 0x802c:lóu # 耬 0x802d:jī # 耭 0x802e:lào # 耮 0x802f:huò # 耯 0x8030:yōu # 耰 0x8031:mò # 耱 0x8032:huái # 耲 0x8033:ěr # 耳 0x8034:yì # 耴 0x8035:dīng # 耵 0x8036:yé,yē # 耶 0x8037:dā # 耷 0x8038:sǒng # 耸 0x8039:qín # 耹 0x803a:yún,yíng # 耺 0x803b:chǐ # 耻 0x803c:dān # 耼 0x803d:dān # 耽 0x803e:hóng # 耾 0x803f:gěng # 耿 0x8040:zhí # 聀 0x8042:niè # 聂 0x8043:dān # 聃 0x8044:zhěn # 聄 0x8045:chè # 聅 0x8046:líng # 聆 0x8047:zhēng # 聇 0x8048:yǒu # 聈 0x8049:wà,tuǐ,zhuó # 聉 0x804a:liáo # 聊 0x804b:lóng # 聋 0x804c:zhí # 职 0x804d:níng # 聍 0x804e:tiāo # 聎 0x804f:ér,nǜ # 聏 0x8050:yà # 聐 0x8051:tiē,zhé # 聑 0x8052:guō # 聒 0x8054:lián # 联 0x8055:hào # 聕 0x8056:shèng # 聖 0x8057:liè # 聗 0x8058:pìn # 聘 0x8059:jīng # 聙 0x805a:jù # 聚 0x805b:bǐ # 聛 0x805c:dǐ,zhì # 聜 0x805d:guó # 聝 0x805e:wén # 聞 0x805f:xù # 聟 0x8060:pīng # 聠 0x8061:cōng # 聡 0x8064:tíng # 聤 0x8065:jǔ # 聥 0x8066:cōng # 聦 0x8067:kuī # 聧 0x8069:kuì # 聩 0x806a:cōng # 聪 0x806b:lián # 聫 0x806c:wēng # 聬 0x806d:kuì # 聭 0x806e:lián # 聮 0x806f:lián # 聯 0x8070:cōng # 聰 0x8071:áo # 聱 0x8072:shēng # 聲 0x8073:sǒng # 聳 0x8074:tīng # 聴 0x8075:kuì # 聵 0x8076:niè # 聶 0x8077:zhí # 職 0x8078:dān # 聸 0x8079:níng # 聹 0x807b:nǐ,jiàn # 聻 0x807c:tīng # 聼 0x807d:tīng # 聽 0x807e:lóng # 聾 0x807f:yù # 聿 0x8080:yù # 肀 0x8081:zhào # 肁 0x8082:sì # 肂 0x8083:sù # 肃 0x8084:yì # 肄 0x8085:sù # 肅 0x8086:sì # 肆 0x8087:zhào # 肇 0x8088:zhào # 肈 0x8089:ròu # 肉 0x808a:yì # 肊 0x808b:lèi,lē # 肋 0x808c:jī # 肌 0x808d:qiú # 肍 0x808e:kěn # 肎 0x808f:cào # 肏 0x8090:gē # 肐 0x8091:bó,dí # 肑 0x8092:huàn # 肒 0x8093:huāng # 肓 0x8094:chǐ # 肔 0x8095:rèn # 肕 0x8096:xiāo,xiào # 肖 0x8097:rǔ # 肗 0x8098:zhǒu # 肘 0x8099:yuān # 肙 0x809a:dù,dǔ # 肚 0x809b:gāng # 肛 0x809c:róng,chēn # 肜 0x809d:gān # 肝 0x809e:chāi # 肞 0x809f:wò # 肟 0x80a0:cháng # 肠 0x80a1:gǔ # 股 0x80a2:zhī # 肢 0x80a3:qín,hán,hàn # 肣 0x80a4:fū # 肤 0x80a5:féi # 肥 0x80a6:bān # 肦 0x80a7:pēi # 肧 0x80a8:pàng,pán,pàn # 肨 0x80a9:jiān # 肩 0x80aa:fáng # 肪 0x80ab:zhūn,chún # 肫 0x80ac:yóu # 肬 0x80ad:nà # 肭 0x80ae:āng # 肮 0x80af:kěn # 肯 0x80b0:rán # 肰 0x80b1:gōng # 肱 0x80b2:yù,yō # 育 0x80b3:wěn # 肳 0x80b4:yáo # 肴 0x80b5:qí # 肵 0x80b6:pí,bǐ,bì # 肶 0x80b7:qiǎn # 肷 0x80b8:xī # 肸 0x80b9:xī # 肹 0x80ba:fèi # 肺 0x80bb:kěn # 肻 0x80bc:jǐng # 肼 0x80bd:tài # 肽 0x80be:shèn # 肾 0x80bf:zhǒng # 肿 0x80c0:zhàng # 胀 0x80c1:xié # 胁 0x80c2:shèn # 胂 0x80c3:wèi # 胃 0x80c4:zhòu # 胄 0x80c5:dié # 胅 0x80c6:dǎn # 胆 0x80c7:fèi,bì # 胇 0x80c8:bá # 胈 0x80c9:bó # 胉 0x80ca:qú # 胊 0x80cb:tián # 胋 0x80cc:bèi,bēi # 背 0x80cd:guā # 胍 0x80ce:tāi # 胎 0x80cf:zǐ,fèi # 胏 0x80d0:fěi,kū # 胐 0x80d1:zhī # 胑 0x80d2:nì # 胒 0x80d3:píng,pēng # 胓 0x80d4:zì # 胔 0x80d5:fū,fú,zhǒu # 胕 0x80d6:pàng,pán,pàn # 胖 0x80d7:zhēn # 胗 0x80d8:xián # 胘 0x80d9:zuò # 胙 0x80da:pēi # 胚 0x80db:jiǎ # 胛 0x80dc:shèng # 胜 0x80dd:zhī # 胝 0x80de:bāo # 胞 0x80df:mǔ # 胟 0x80e0:qū # 胠 0x80e1:hú # 胡 0x80e2:qià # 胢 0x80e3:chǐ # 胣 0x80e4:yìn # 胤 0x80e5:xū # 胥 0x80e6:yāng # 胦 0x80e7:lóng # 胧 0x80e8:dòng # 胨 0x80e9:kǎ # 胩 0x80ea:lú # 胪 0x80eb:jìng # 胫 0x80ec:nǔ # 胬 0x80ed:yān # 胭 0x80ee:pāng # 胮 0x80ef:kuà # 胯 0x80f0:yí # 胰 0x80f1:guāng # 胱 0x80f2:hǎi # 胲 0x80f3:gē,gé # 胳 0x80f4:dòng # 胴 0x80f5:chī # 胵 0x80f6:jiāo # 胶 0x80f7:xiōng # 胷 0x80f8:xiōng # 胸 0x80f9:ér # 胹 0x80fa:àn # 胺 0x80fb:héng # 胻 0x80fc:pián # 胼 0x80fd:néng,nài # 能 0x80fe:zì # 胾 0x8100:zhēng # 脀 0x8101:tiǎo # 脁 0x8102:zhī # 脂 0x8103:cuì # 脃 0x8104:méi # 脄 0x8105:xié # 脅 0x8106:cuì # 脆 0x8107:xié # 脇 0x8108:mài,mò # 脈 0x8109:mài,mò # 脉 0x810a:jǐ # 脊 0x810d:kuài # 脍 0x810e:sà # 脎 0x810f:zàng # 脏 0x8110:qí # 脐 0x8111:nǎo # 脑 0x8112:mǐ # 脒 0x8113:nóng # 脓 0x8114:luán # 脔 0x8115:wàn # 脕 0x8116:bó # 脖 0x8117:wěn # 脗 0x8118:wǎn # 脘 0x8119:xiū # 脙 0x811a:jiǎo,jué # 脚 0x811b:jìng # 脛 0x811c:róu # 脜 0x811d:hēng # 脝 0x811e:cuǒ # 脞 0x811f:liè # 脟 0x8120:shān # 脠 0x8121:tǐng # 脡 0x8122:méi # 脢 0x8123:chún # 脣 0x8124:shèn # 脤 0x8125:jiá # 脥 0x8126:tè # 脦 0x8127:juān # 脧 0x8128:cù # 脨 0x8129:xiū # 脩 0x812a:xìn # 脪 0x812b:tuō # 脫 0x812c:pāo # 脬 0x812d:chéng # 脭 0x812e:něi # 脮 0x812f:fǔ,pǔ # 脯 0x8130:dòu # 脰 0x8131:tuō # 脱 0x8132:niào # 脲 0x8134:pǐ # 脴 0x8135:gǔ # 脵 0x8136:luó # 脶 0x8137:lì # 脷 0x8138:liǎn # 脸 0x8139:zhàng # 脹 0x813a:cuī # 脺 0x813b:jiē # 脻 0x813c:liǎng # 脼 0x813d:shuí # 脽 0x813e:pí # 脾 0x813f:biāo # 脿 0x8140:lún # 腀 0x8141:pián # 腁 0x8142:guò # 腂 0x8143:juàn # 腃 0x8144:chuí # 腄 0x8145:dàn # 腅 0x8146:tiǎn # 腆 0x8147:něi # 腇 0x8148:jīng # 腈 0x8149:nái # 腉 0x814a:là,xī # 腊 0x814b:yè # 腋 0x814c:ā,yān # 腌 0x814d:rèn # 腍 0x814e:shèn # 腎 0x814f:zhuì # 腏 0x8150:fǔ # 腐 0x8151:fǔ # 腑 0x8152:jū # 腒 0x8153:féi # 腓 0x8154:qiāng # 腔 0x8155:wàn # 腕 0x8156:dòng # 腖 0x8157:pí # 腗 0x8158:guó # 腘 0x8159:zōng # 腙 0x815a:dìng # 腚 0x815b:wò # 腛 0x815c:méi # 腜 0x815d:ruǎn # 腝 0x815e:zhuàn # 腞 0x815f:chì # 腟 0x8160:còu # 腠 0x8161:luó # 腡 0x8162:ǒu # 腢 0x8163:dì # 腣 0x8164:ān # 腤 0x8165:xīng # 腥 0x8166:nǎo # 腦 0x8167:shù # 腧 0x8168:shuàn # 腨 0x8169:nǎn # 腩 0x816a:yùn # 腪 0x816b:zhǒng # 腫 0x816c:róu # 腬 0x816d:è # 腭 0x816e:sāi # 腮 0x816f:tú # 腯 0x8170:yāo # 腰 0x8171:jiàn # 腱 0x8172:wěi # 腲 0x8173:jiǎo,jué # 腳 0x8174:yú # 腴 0x8175:jiā # 腵 0x8176:duàn # 腶 0x8177:bì # 腷 0x8178:cháng # 腸 0x8179:fù # 腹 0x817a:xiàn # 腺 0x817b:nì # 腻 0x817c:miǎn # 腼 0x817d:wà # 腽 0x817e:téng # 腾 0x817f:tuǐ # 腿 0x8180:bǎng,páng # 膀 0x8181:qiǎn # 膁 0x8182:lǚ # 膂 0x8183:wà # 膃 0x8184:shòu # 膄 0x8185:táng # 膅 0x8186:sù # 膆 0x8187:zhuì # 膇 0x8188:gé # 膈 0x8189:yì # 膉 0x818a:bó # 膊 0x818b:liáo # 膋 0x818c:jí # 膌 0x818d:pí # 膍 0x818e:xié # 膎 0x818f:gāo,gào # 膏 0x8190:lǚ # 膐 0x8191:bìn # 膑 0x8193:cháng # 膓 0x8194:lù,biāo # 膔 0x8195:guó # 膕 0x8196:pāng # 膖 0x8197:chuái # 膗 0x8198:biāo # 膘 0x8199:jiǎng # 膙 0x819a:fū # 膚 0x819b:táng # 膛 0x819c:mó # 膜 0x819d:xī # 膝 0x819e:zhuān,chuán,chún,zhuǎn # 膞 0x819f:lǜ # 膟 0x81a0:jiāo # 膠 0x81a1:yìng # 膡 0x81a2:lǘ # 膢 0x81a3:zhì # 膣 0x81a5:cūn # 膥 0x81a6:lìn # 膦 0x81a7:tóng # 膧 0x81a8:péng # 膨 0x81a9:nì # 膩 0x81aa:chuài # 膪 0x81ab:liáo # 膫 0x81ac:cuì # 膬 0x81ad:kuì # 膭 0x81ae:xiāo # 膮 0x81af:tēng # 膯 0x81b0:fán,pán # 膰 0x81b1:zhí # 膱 0x81b2:jiāo # 膲 0x81b3:shàn # 膳 0x81b4:hū,wǔ # 膴 0x81b5:cuì # 膵 0x81b6:rùn # 膶 0x81b7:xiāng # 膷 0x81b8:suǐ # 膸 0x81b9:fèn # 膹 0x81ba:yīng # 膺 0x81bb:shān,dàn # 膻 0x81bc:zhuā # 膼 0x81bd:dǎn # 膽 0x81be:kuài # 膾 0x81bf:nóng # 膿 0x81c0:tún # 臀 0x81c1:lián # 臁 0x81c2:bì,bei # 臂 0x81c3:yōng # 臃 0x81c4:jué # 臄 0x81c5:chù # 臅 0x81c6:yì # 臆 0x81c7:juǎn # 臇 0x81c8:là,gé # 臈 0x81c9:liǎn # 臉 0x81ca:sāo,sào # 臊 0x81cb:tún # 臋 0x81cc:gǔ # 臌 0x81cd:qí # 臍 0x81ce:cuì # 臎 0x81cf:bìn # 臏 0x81d0:xūn # 臐 0x81d1:nào # 臑 0x81d2:wò,yuè # 臒 0x81d3:zàng # 臓 0x81d4:xiàn # 臔 0x81d5:biāo # 臕 0x81d6:xìng # 臖 0x81d7:kuān # 臗 0x81d8:là # 臘 0x81d9:yān # 臙 0x81da:lú # 臚 0x81db:huò # 臛 0x81dc:zā # 臜 0x81dd:luǒ # 臝 0x81de:qú # 臞 0x81df:zàng # 臟 0x81e0:luán # 臠 0x81e1:ní,luán # 臡 0x81e2:zā # 臢 0x81e3:chén # 臣 0x81e4:qiān,xián # 臤 0x81e5:wò # 臥 0x81e6:guàng,jiǒng # 臦 0x81e7:zāng,zàng,cáng # 臧 0x81e8:lín # 臨 0x81e9:guǎng,jiǒng # 臩 0x81ea:zì # 自 0x81eb:jiǎo # 臫 0x81ec:niè # 臬 0x81ed:chòu,xiù # 臭 0x81ee:jì # 臮 0x81ef:gāo # 臯 0x81f0:chòu # 臰 0x81f1:mián,biān # 臱 0x81f2:niè # 臲 0x81f3:zhì # 至 0x81f4:zhì # 致 0x81f5:gé # 臵 0x81f6:jiàn # 臶 0x81f7:dié,zhí # 臷 0x81f8:zhī,jìn # 臸 0x81f9:xiū # 臹 0x81fa:tái # 臺 0x81fb:zhēn # 臻 0x81fc:jiù # 臼 0x81fd:xiàn # 臽 0x81fe:yú # 臾 0x81ff:chā # 臿 0x8200:yǎo # 舀 0x8201:yú # 舁 0x8202:chōng # 舂 0x8203:xì # 舃 0x8204:xì # 舄 0x8205:jiù # 舅 0x8206:yú # 舆 0x8207:yǔ # 與 0x8208:xīng # 興 0x8209:jǔ # 舉 0x820a:jiù # 舊 0x820b:xìn # 舋 0x820c:shé # 舌 0x820d:shě,shè # 舍 0x820f:jiǔ # 舏 0x8210:shì # 舐 0x8211:tān # 舑 0x8212:shū # 舒 0x8213:shì # 舓 0x8214:tiǎn # 舔 0x8215:tàn # 舕 0x8216:pù # 舖 0x8217:pù # 舗 0x8218:guǎn # 舘 0x8219:huà # 舙 0x821a:tiàn # 舚 0x821b:chuǎn # 舛 0x821c:shùn # 舜 0x821d:xiá # 舝 0x821e:wǔ # 舞 0x821f:zhōu # 舟 0x8220:dāo # 舠 0x8221:chuán # 舡 0x8222:shān # 舢 0x8223:yǐ # 舣 0x8225:pā # 舥 0x8226:tài # 舦 0x8227:fán # 舧 0x8228:bǎn # 舨 0x8229:chuán # 舩 0x822a:háng # 航 0x822b:fǎng # 舫 0x822c:bān,bō,pán # 般 0x822d:bǐ # 舭 0x822f:zhōng # 舯 0x8230:jiàn # 舰 0x8231:cāng # 舱 0x8232:líng # 舲 0x8233:zhú # 舳 0x8234:zé # 舴 0x8235:duò # 舵 0x8236:bó # 舶 0x8237:xián # 舷 0x8238:gě # 舸 0x8239:chuán # 船 0x823a:xiá # 舺 0x823b:lú # 舻 0x823c:qióng # 舼 0x823d:páng # 舽 0x823e:xī # 舾 0x8240:fú # 艀 0x8241:zào # 艁 0x8242:féng # 艂 0x8243:lí # 艃 0x8244:shāo # 艄 0x8245:yú # 艅 0x8246:láng # 艆 0x8247:tǐng # 艇 0x8249:wěi # 艉 0x824a:bó # 艊 0x824b:měng # 艋 0x824c:niàn # 艌 0x824d:jū # 艍 0x824e:huáng # 艎 0x824f:shǒu # 艏 0x8250:kè # 艐 0x8251:biàn # 艑 0x8252:mù # 艒 0x8253:dié # 艓 0x8255:bàng # 艕 0x8256:chā # 艖 0x8257:yì # 艗 0x8258:sōu # 艘 0x8259:cāng # 艙 0x825a:cáo # 艚 0x825b:lóu # 艛 0x825c:dài # 艜 0x825e:yào # 艞 0x825f:chōng # 艟 0x8261:dāng # 艡 0x8262:qiáng # 艢 0x8263:lǔ # 艣 0x8264:yǐ # 艤 0x8265:jí # 艥 0x8266:jiàn # 艦 0x8267:huò # 艧 0x8268:méng # 艨 0x8269:qí # 艩 0x826a:lǔ # 艪 0x826b:lú # 艫 0x826c:chán # 艬 0x826d:shuāng # 艭 0x826e:gèn # 艮 0x826f:liáng # 良 0x8270:jiān # 艰 0x8271:jiān # 艱 0x8272:sè,shǎi # 色 0x8273:yàn # 艳 0x8274:fú # 艴 0x8275:pīng # 艵 0x8276:yàn # 艶 0x8277:yàn # 艷 0x8278:cǎo # 艸 0x827a:yì # 艺 0x827b:lè # 艻 0x827c:dǐng # 艼 0x827d:jiāo,qiú # 艽 0x827e:ài,yì # 艾 0x827f:nǎi # 艿 0x8280:tiáo # 芀 0x8281:qiú # 芁 0x8282:jié,jiē # 节 0x8283:péng # 芃 0x8284:wán # 芄 0x8285:yì # 芅 0x8286:chāi,chā # 芆 0x8287:mián # 芇 0x8288:mǐ # 芈 0x8289:gǎn # 芉 0x828a:qiān # 芊 0x828b:yù # 芋 0x828c:yù # 芌 0x828d:sháo # 芍 0x828e:xiōng # 芎 0x828f:dù # 芏 0x8290:hù,xià # 芐 0x8291:qǐ # 芑 0x8292:máng # 芒 0x8293:zì,zǐ # 芓 0x8294:huì,hū # 芔 0x8295:suī # 芕 0x8296:zhì # 芖 0x8297:xiāng # 芗 0x8298:bì,pí # 芘 0x8299:fú # 芙 0x829a:tún,chūn # 芚 0x829b:wěi # 芛 0x829c:wú # 芜 0x829d:zhī # 芝 0x829e:qì # 芞 0x829f:shān # 芟 0x82a0:wén # 芠 0x82a1:qiàn # 芡 0x82a2:rén # 芢 0x82a3:fú # 芣 0x82a4:kōu # 芤 0x82a5:jiè,gài # 芥 0x82a6:lú # 芦 0x82a7:xù,zhù # 芧 0x82a8:jī # 芨 0x82a9:qín # 芩 0x82aa:qí # 芪 0x82ab:yuán,yán # 芫 0x82ac:fēn # 芬 0x82ad:bā # 芭 0x82ae:ruì # 芮 0x82af:xīn,xìn # 芯 0x82b0:jì # 芰 0x82b1:huā # 花 0x82b2:lún,huā # 芲 0x82b3:fāng # 芳 0x82b4:wù,hū # 芴 0x82b5:jué # 芵 0x82b6:gōu,gǒu # 芶 0x82b7:zhǐ # 芷 0x82b8:yún # 芸 0x82b9:qín # 芹 0x82ba:ǎo # 芺 0x82bb:chú # 芻 0x82bc:máo,mào # 芼 0x82bd:yá # 芽 0x82be:fèi,fú # 芾 0x82bf:réng # 芿 0x82c0:háng # 苀 0x82c1:cōng # 苁 0x82c2:chán,yín # 苂 0x82c3:yǒu # 苃 0x82c4:biàn # 苄 0x82c5:yì # 苅 0x82c7:wěi # 苇 0x82c8:lì # 苈 0x82c9:pǐ # 苉 0x82ca:è # 苊 0x82cb:xiàn # 苋 0x82cc:cháng # 苌 0x82cd:cāng # 苍 0x82ce:zhù # 苎 0x82cf:sū,sù # 苏 0x82d0:dì,tí # 苐 0x82d1:yuàn # 苑 0x82d2:rǎn # 苒 0x82d3:líng # 苓 0x82d4:tái,tāi # 苔 0x82d5:tiáo,sháo # 苕 0x82d6:dí # 苖 0x82d7:miáo # 苗 0x82d8:qǐng # 苘 0x82d9:lì,jī # 苙 0x82da:yòng # 苚 0x82db:kē,hē # 苛 0x82dc:mù # 苜 0x82dd:bèi # 苝 0x82de:bāo # 苞 0x82df:gǒu # 苟 0x82e0:mín # 苠 0x82e1:yǐ # 苡 0x82e2:yǐ # 苢 0x82e3:jù,qǔ # 苣 0x82e4:piě # 苤 0x82e5:ruò,rě # 若 0x82e6:kǔ # 苦 0x82e7:zhù,níng # 苧 0x82e8:nǐ # 苨 0x82e9:pā,bó # 苩 0x82ea:bǐng # 苪 0x82eb:shān,shàn # 苫 0x82ec:xiú # 苬 0x82ed:yǎo # 苭 0x82ee:xiān # 苮 0x82ef:běn # 苯 0x82f0:hóng # 苰 0x82f1:yīng # 英 0x82f2:zuó,zhǎ # 苲 0x82f3:dōng # 苳 0x82f4:jū,chá # 苴 0x82f5:dié # 苵 0x82f6:nié # 苶 0x82f7:gān # 苷 0x82f8:hū # 苸 0x82f9:píng,pēng # 苹 0x82fa:méi # 苺 0x82fb:fú # 苻 0x82fc:shēng,ruí # 苼 0x82fd:gū # 苽 0x82fe:bì # 苾 0x82ff:wèi # 苿 0x8300:fú # 茀 0x8301:zhuó # 茁 0x8302:mào # 茂 0x8303:fàn # 范 0x8304:qié,jiā # 茄 0x8305:máo # 茅 0x8306:máo # 茆 0x8307:bá # 茇 0x8308:zǐ,cí # 茈 0x8309:mò # 茉 0x830a:zī # 茊 0x830b:zhǐ # 茋 0x830c:chí # 茌 0x830d:jì # 茍 0x830e:jīng # 茎 0x830f:lóng # 茏 0x8311:niǎo # 茑 0x8313:xué # 茓 0x8314:yíng # 茔 0x8315:qióng # 茕 0x8316:gè # 茖 0x8317:míng # 茗 0x8318:lì # 茘 0x8319:róng # 茙 0x831a:yìn # 茚 0x831b:gèn # 茛 0x831c:qiàn,xī # 茜 0x831d:chǎi,zhǐ # 茝 0x831e:chén # 茞 0x831f:yù # 茟 0x8320:hāo # 茠 0x8321:zì # 茡 0x8322:liè # 茢 0x8323:wú # 茣 0x8324:jì # 茤 0x8325:guī # 茥 0x8326:cì # 茦 0x8327:jiǎn # 茧 0x8328:cí # 茨 0x8329:hòu # 茩 0x832a:guāng # 茪 0x832b:máng # 茫 0x832c:chá # 茬 0x832d:jiāo # 茭 0x832e:jiāo # 茮 0x832f:fú # 茯 0x8330:yú # 茰 0x8331:zhū # 茱 0x8332:zī # 茲 0x8333:jiāng # 茳 0x8334:huí # 茴 0x8335:yīn # 茵 0x8336:chá # 茶 0x8337:fá # 茷 0x8338:róng # 茸 0x8339:rú # 茹 0x833a:chōng # 茺 0x833b:mǎng # 茻 0x833c:tóng # 茼 0x833d:zhòng # 茽 0x833f:zhú # 茿 0x8340:xún # 荀 0x8341:huán # 荁 0x8342:fū # 荂 0x8343:quán # 荃 0x8344:gāi # 荄 0x8345:dá # 荅 0x8346:jīng # 荆 0x8347:xìng # 荇 0x8348:chuǎn # 荈 0x8349:cǎo # 草 0x834a:jīng # 荊 0x834b:ér # 荋 0x834c:àn # 荌 0x834d:qiáo # 荍 0x834e:chí # 荎 0x834f:rěn # 荏 0x8350:jiàn # 荐 0x8351:yí,tí # 荑 0x8352:huāng # 荒 0x8353:píng # 荓 0x8354:lì # 荔 0x8355:jīn # 荕 0x8356:lǎo # 荖 0x8357:shù # 荗 0x8358:zhuāng # 荘 0x8359:dá # 荙 0x835a:jiá # 荚 0x835b:ráo # 荛 0x835c:bì # 荜 0x835d:cè # 荝 0x835e:qiáo # 荞 0x835f:huì # 荟 0x8360:jì,qí # 荠 0x8361:dàng # 荡 0x8363:róng # 荣 0x8364:hūn,xūn # 荤 0x8365:xíng,yīng # 荥 0x8366:luò # 荦 0x8367:yíng # 荧 0x8368:qián,xún # 荨 0x8369:jìn # 荩 0x836a:sūn # 荪 0x836b:yīn,yìn # 荫 0x836c:mǎi # 荬 0x836d:hóng # 荭 0x836e:zhòu # 荮 0x836f:yào # 药 0x8370:dù # 荰 0x8371:wěi # 荱 0x8372:lí # 荲 0x8373:dòu # 荳 0x8374:fū # 荴 0x8375:rěn # 荵 0x8376:yín # 荶 0x8377:hé # 荷 0x8378:bí # 荸 0x8379:bù # 荹 0x837a:yǔn # 荺 0x837b:dí # 荻 0x837c:tú # 荼 0x837d:suī # 荽 0x837e:suī # 荾 0x837f:chéng # 荿 0x8380:chén # 莀 0x8381:wú # 莁 0x8382:bié # 莂 0x8383:xī # 莃 0x8384:gěng # 莄 0x8385:lì # 莅 0x8386:pú # 莆 0x8387:zhù # 莇 0x8388:mò # 莈 0x8389:lì # 莉 0x838a:zhuāng # 莊 0x838b:zuó # 莋 0x838c:tuō # 莌 0x838d:qiú # 莍 0x838e:suō,shā # 莎 0x838f:suō # 莏 0x8390:chén # 莐 0x8391:péng,fēng # 莑 0x8392:jǔ # 莒 0x8393:méi # 莓 0x8394:méng # 莔 0x8395:xìng # 莕 0x8396:jìng # 莖 0x8397:chē # 莗 0x8398:shēn,xīn # 莘 0x8399:jūn # 莙 0x839a:yán # 莚 0x839b:tíng # 莛 0x839c:yóu # 莜 0x839d:cuò # 莝 0x839e:guān,guǎn,wǎn # 莞 0x839f:hàn # 莟 0x83a0:yǒu # 莠 0x83a1:cuò # 莡 0x83a2:jiá # 莢 0x83a3:wáng # 莣 0x83a4:sù,yóu # 莤 0x83a5:niǔ # 莥 0x83a6:shāo,xiāo # 莦 0x83a7:xiàn # 莧 0x83a8:làng,liáng # 莨 0x83a9:fú,piǎo # 莩 0x83aa:é # 莪 0x83ab:mò,mù # 莫 0x83ac:wèn,wǎn,miǎn # 莬 0x83ad:jié # 莭 0x83ae:nán # 莮 0x83af:mù # 莯 0x83b0:kǎn # 莰 0x83b1:lái # 莱 0x83b2:lián # 莲 0x83b3:shì,shí # 莳 0x83b4:wō # 莴 0x83b6:xiān,liǎn # 莶 0x83b7:huò # 获 0x83b8:yóu # 莸 0x83b9:yíng # 莹 0x83ba:yīng # 莺 0x83bc:chún # 莼 0x83bd:mǎng # 莽 0x83be:mǎng # 莾 0x83bf:cì # 莿 0x83c0:wǎn,yùn,yù # 菀 0x83c1:jīng # 菁 0x83c2:dì # 菂 0x83c3:qú # 菃 0x83c4:dōng # 菄 0x83c5:jiān # 菅 0x83c6:zōu,chù # 菆 0x83c7:gū # 菇 0x83c8:lā # 菈 0x83c9:lù # 菉 0x83ca:jú # 菊 0x83cb:wèi # 菋 0x83cc:jūn,jùn # 菌 0x83cd:niè,rěn # 菍 0x83ce:kūn # 菎 0x83cf:hé # 菏 0x83d0:pú # 菐 0x83d1:zī,zì,zāi # 菑 0x83d2:gǎo # 菒 0x83d3:guǒ # 菓 0x83d4:fú # 菔 0x83d5:lún # 菕 0x83d6:chāng # 菖 0x83d7:chóu # 菗 0x83d8:sōng # 菘 0x83d9:chuí # 菙 0x83da:zhàn # 菚 0x83db:mén # 菛 0x83dc:cài # 菜 0x83dd:bá # 菝 0x83de:lí # 菞 0x83df:tù,tú # 菟 0x83e0:bō # 菠 0x83e1:hàn # 菡 0x83e2:bào # 菢 0x83e3:qìn # 菣 0x83e4:juǎn # 菤 0x83e5:xī # 菥 0x83e6:qín # 菦 0x83e7:dǐ # 菧 0x83e8:jiē,shà # 菨 0x83e9:pú # 菩 0x83ea:dàng # 菪 0x83eb:jǐn # 菫 0x83ec:qiáo,zhǎo # 菬 0x83ed:tái,zhī,chí # 菭 0x83ee:gēng # 菮 0x83ef:huá,huà,huā # 華 0x83f0:gū # 菰 0x83f1:líng # 菱 0x83f2:fēi,fěi # 菲 0x83f3:qín,qīn,jīn # 菳 0x83f4:ān # 菴 0x83f5:wǎng # 菵 0x83f6:běng # 菶 0x83f7:zhǒu # 菷 0x83f8:yān # 菸 0x83f9:zū # 菹 0x83fa:jiān # 菺 0x83fb:lǐn,má # 菻 0x83fc:tǎn # 菼 0x83fd:shū # 菽 0x83fe:tián,tiàn # 菾 0x83ff:dào # 菿 0x8400:hǔ # 萀 0x8401:qí # 萁 0x8402:hé # 萂 0x8403:cuì # 萃 0x8404:táo # 萄 0x8405:chūn # 萅 0x8406:bì # 萆 0x8407:cháng # 萇 0x8408:huán # 萈 0x8409:fèi # 萉 0x840a:lái # 萊 0x840b:qī # 萋 0x840c:méng # 萌 0x840d:píng # 萍 0x840e:wěi # 萎 0x840f:dàn # 萏 0x8410:shà # 萐 0x8411:huán # 萑 0x8412:yǎn # 萒 0x8413:yí # 萓 0x8414:tiáo # 萔 0x8415:qí # 萕 0x8416:wǎn # 萖 0x8417:cè # 萗 0x8418:nài # 萘 0x841a:tuò # 萚 0x841b:jiū # 萛 0x841c:tiē # 萜 0x841d:luó # 萝 0x8420:pān # 萠 0x8424:yíng # 萤 0x8425:yíng # 营 0x8426:yíng # 萦 0x8427:xiāo # 萧 0x8428:sà # 萨 0x8429:qiū # 萩 0x842a:kē # 萪 0x842b:xiāng # 萫 0x842c:wàn # 萬 0x842d:yǔ # 萭 0x842e:yú # 萮 0x842f:fù # 萯 0x8430:liàn # 萰 0x8431:xuān # 萱 0x8432:xuān # 萲 0x8433:nǎn # 萳 0x8434:cè # 萴 0x8435:wō # 萵 0x8436:chǔn # 萶 0x8437:shāo # 萷 0x8438:yú # 萸 0x8439:biān # 萹 0x843a:mào # 萺 0x843b:ān # 萻 0x843c:è # 萼 0x843d:là,luò,lào # 落 0x843e:yíng # 萾 0x843f:kuò # 萿 0x8440:kuò # 葀 0x8441:jiāng # 葁 0x8442:miǎn # 葂 0x8443:zuò # 葃 0x8444:zuò # 葄 0x8445:zū # 葅 0x8446:bǎo # 葆 0x8447:róu # 葇 0x8448:xǐ # 葈 0x8449:yè # 葉 0x844a:ān # 葊 0x844b:qú # 葋 0x844c:jiān # 葌 0x844d:fú # 葍 0x844e:lǜ # 葎 0x844f:jīng # 葏 0x8450:pén # 葐 0x8451:fēng # 葑 0x8452:hóng # 葒 0x8453:hóng # 葓 0x8454:hóu # 葔 0x8455:xìng # 葕 0x8456:tū # 葖 0x8457:zhù,zhuó,zhe # 著 0x8458:zī # 葘 0x8459:xiāng # 葙 0x845a:shèn,rèn # 葚 0x845b:gé,gě # 葛 0x845c:qiā # 葜 0x845d:qíng # 葝 0x845e:mǐ # 葞 0x845f:huáng # 葟 0x8460:shēn # 葠 0x8461:pú # 葡 0x8462:gài # 葢 0x8463:dǒng # 董 0x8464:zhòu # 葤 0x8465:qián # 葥 0x8466:wěi # 葦 0x8467:bó # 葧 0x8468:wēi # 葨 0x8469:pā # 葩 0x846a:jì # 葪 0x846b:hú # 葫 0x846c:zàng # 葬 0x846d:jiā # 葭 0x846e:duàn # 葮 0x846f:yào # 葯 0x8470:jùn # 葰 0x8471:cōng # 葱 0x8472:quán # 葲 0x8473:wēi # 葳 0x8474:zhēn # 葴 0x8475:kuí # 葵 0x8476:tíng # 葶 0x8477:hūn # 葷 0x8478:xǐ # 葸 0x8479:shī # 葹 0x847a:qì # 葺 0x847b:lán # 葻 0x847c:zōng # 葼 0x847d:yāo # 葽 0x847e:yuān # 葾 0x847f:méi # 葿 0x8480:yūn # 蒀 0x8481:shù # 蒁 0x8482:dì # 蒂 0x8483:zhuàn # 蒃 0x8484:guān # 蒄 0x8486:xuē # 蒆 0x8487:chǎn # 蒇 0x8488:kǎi # 蒈 0x8489:kuì,kuài # 蒉 0x848b:jiǎng # 蒋 0x848c:lóu # 蒌 0x848d:wěi # 蒍 0x848e:pài # 蒎 0x8490:sōu # 蒐 0x8491:yīn # 蒑 0x8492:shī # 蒒 0x8493:chún # 蒓 0x8494:shì,shí # 蒔 0x8495:yūn # 蒕 0x8496:zhēn # 蒖 0x8497:làng # 蒗 0x8498:rú,ná # 蒘 0x8499:mēng,méng,měng # 蒙 0x849a:lì # 蒚 0x849b:quē # 蒛 0x849c:suàn # 蒜 0x849d:yuán,huán # 蒝 0x849e:lì # 蒞 0x849f:jǔ # 蒟 0x84a0:xī # 蒠 0x84a1:bàng # 蒡 0x84a2:chú # 蒢 0x84a3:xú,shú # 蒣 0x84a4:tú # 蒤 0x84a5:liú # 蒥 0x84a6:huò # 蒦 0x84a7:diǎn # 蒧 0x84a8:qiàn # 蒨 0x84a9:zū,jù # 蒩 0x84aa:pò # 蒪 0x84ab:cuó # 蒫 0x84ac:yuān # 蒬 0x84ad:chú # 蒭 0x84ae:yù # 蒮 0x84af:kuǎi # 蒯 0x84b0:pán # 蒰 0x84b1:pú # 蒱 0x84b2:pú # 蒲 0x84b3:nà # 蒳 0x84b4:shuò # 蒴 0x84b5:xí,xì # 蒵 0x84b6:fén # 蒶 0x84b7:yún # 蒷 0x84b8:zhēng # 蒸 0x84b9:jiān # 蒹 0x84ba:jí # 蒺 0x84bb:ruò # 蒻 0x84bc:cāng # 蒼 0x84bd:ēn # 蒽 0x84be:mí # 蒾 0x84bf:hāo # 蒿 0x84c0:sūn # 蓀 0x84c1:zhēn # 蓁 0x84c2:míng # 蓂 0x84c3:sōu,sǒu # 蓃 0x84c4:xù # 蓄 0x84c5:liú # 蓅 0x84c6:xí # 蓆 0x84c7:gū # 蓇 0x84c8:láng # 蓈 0x84c9:róng # 蓉 0x84ca:wěng # 蓊 0x84cb:gài,gě,hé # 蓋 0x84cc:cuò # 蓌 0x84cd:shī # 蓍 0x84ce:táng # 蓎 0x84cf:luǒ # 蓏 0x84d0:rù # 蓐 0x84d1:suō # 蓑 0x84d2:xuān # 蓒 0x84d3:bèi # 蓓 0x84d4:yǎo,zhuó # 蓔 0x84d5:guì # 蓕 0x84d6:bì # 蓖 0x84d7:zǒng # 蓗 0x84d8:gǔn # 蓘 0x84da:tiáo # 蓚 0x84db:cè # 蓛 0x84dd:lán # 蓝 0x84df:jì # 蓟 0x84e0:lí # 蓠 0x84e1:shēn # 蓡 0x84e2:lǎng # 蓢 0x84e3:yù # 蓣 0x84e5:yíng # 蓥 0x84e6:mò # 蓦 0x84e7:diào,tiáo,dí # 蓧 0x84e8:tiáo # 蓨 0x84e9:mǎo # 蓩 0x84ea:tōng # 蓪 0x84eb:zhú # 蓫 0x84ec:péng # 蓬 0x84ed:ān # 蓭 0x84ee:lián # 蓮 0x84ef:cōng # 蓯 0x84f0:xǐ # 蓰 0x84f1:píng # 蓱 0x84f2:qiū,xū,fū # 蓲 0x84f3:jǐn # 蓳 0x84f4:chún # 蓴 0x84f5:jié # 蓵 0x84f6:wéi # 蓶 0x84f7:tuī # 蓷 0x84f8:cáo # 蓸 0x84f9:yù # 蓹 0x84fa:yì # 蓺 0x84fb:zí,jú # 蓻 0x84fc:liǎo,lù # 蓼 0x84fd:bì # 蓽 0x84fe:lǔ # 蓾 0x84ff:xù # 蓿 0x8500:bù # 蔀 0x8501:zhāng # 蔁 0x8502:léi # 蔂 0x8503:qiáng,jiàng # 蔃 0x8504:màn # 蔄 0x8505:yán # 蔅 0x8506:líng # 蔆 0x8507:jì # 蔇 0x8508:biāo # 蔈 0x8509:gǔn # 蔉 0x850a:hàn # 蔊 0x850b:dí # 蔋 0x850c:sù # 蔌 0x850d:lù # 蔍 0x850e:shè # 蔎 0x850f:shāng # 蔏 0x8510:dí # 蔐 0x8511:miè # 蔑 0x8512:hūn # 蔒 0x8513:màn,wàn # 蔓 0x8514:bo # 蔔 0x8515:dì # 蔕 0x8516:cuó # 蔖 0x8517:zhè # 蔗 0x8518:shēn # 蔘 0x8519:xuàn # 蔙 0x851a:wèi,yù # 蔚 0x851b:hú # 蔛 0x851c:áo # 蔜 0x851d:mǐ # 蔝 0x851e:lóu # 蔞 0x851f:cù # 蔟 0x8520:zhōng # 蔠 0x8521:cài # 蔡 0x8522:pó # 蔢 0x8523:jiǎng # 蔣 0x8524:mì # 蔤 0x8525:cōng # 蔥 0x8526:niǎo # 蔦 0x8527:huì # 蔧 0x8528:juàn # 蔨 0x8529:yín # 蔩 0x852a:jiān # 蔪 0x852b:niān # 蔫 0x852c:shū # 蔬 0x852d:yīn # 蔭 0x852e:guó # 蔮 0x852f:chén # 蔯 0x8530:hù # 蔰 0x8531:shā # 蔱 0x8532:kòu # 蔲 0x8533:qiàn # 蔳 0x8534:má # 蔴 0x8535:zàng # 蔵 0x8537:qiáng # 蔷 0x8538:dōu # 蔸 0x8539:liǎn # 蔹 0x853a:lìn # 蔺 0x853b:kòu # 蔻 0x853c:ǎi # 蔼 0x853d:bì # 蔽 0x853e:lí # 蔾 0x853f:wěi # 蔿 0x8540:jí # 蕀 0x8541:qián,xún # 蕁 0x8542:shèng # 蕂 0x8543:fān,fán,bō # 蕃 0x8544:méng # 蕄 0x8545:ǒu # 蕅 0x8546:chǎn # 蕆 0x8547:diǎn # 蕇 0x8548:xùn # 蕈 0x8549:jiāo,qiáo # 蕉 0x854a:ruǐ # 蕊 0x854b:ruǐ # 蕋 0x854c:lěi # 蕌 0x854d:yú # 蕍 0x854e:qiáo # 蕎 0x854f:zhū # 蕏 0x8550:huá # 蕐 0x8551:jiān # 蕑 0x8552:mǎi # 蕒 0x8553:yún # 蕓 0x8554:bāo # 蕔 0x8555:yóu # 蕕 0x8556:qú # 蕖 0x8557:lù # 蕗 0x8558:ráo # 蕘 0x8559:huì # 蕙 0x855a:è # 蕚 0x855b:tí # 蕛 0x855c:fěi # 蕜 0x855d:jué # 蕝 0x855e:zuì # 蕞 0x855f:fà # 蕟 0x8560:rú # 蕠 0x8561:fén # 蕡 0x8562:kuì # 蕢 0x8563:shùn # 蕣 0x8564:ruí # 蕤 0x8565:yǎ # 蕥 0x8566:xū # 蕦 0x8567:fù # 蕧 0x8568:jué # 蕨 0x8569:dàng # 蕩 0x856a:wú # 蕪 0x856b:dǒng # 蕫 0x856c:sī # 蕬 0x856d:xiāo # 蕭 0x856e:xì # 蕮 0x856f:sà # 蕯 0x8570:yùn,wēn # 蕰 0x8572:qí # 蕲 0x8573:jiān # 蕳 0x8574:yùn # 蕴 0x8575:sūn # 蕵 0x8576:líng # 蕶 0x8577:yù # 蕷 0x8578:xiá # 蕸 0x8579:wèng # 蕹 0x857a:jí # 蕺 0x857b:hòng # 蕻 0x857c:sì # 蕼 0x857d:nóng # 蕽 0x857e:lěi # 蕾 0x857f:xuān # 蕿 0x8580:yùn # 薀 0x8581:yù # 薁 0x8582:xí,xiào # 薂 0x8583:hào # 薃 0x8584:báo,bó,bò # 薄 0x8585:hāo # 薅 0x8586:ài # 薆 0x8587:wēi # 薇 0x8588:huì # 薈 0x8589:huì # 薉 0x858a:jì # 薊 0x858b:cí,zī # 薋 0x858c:xiāng # 薌 0x858d:wàn,luàn # 薍 0x858e:miè # 薎 0x858f:yì # 薏 0x8590:léng # 薐 0x8591:jiāng # 薑 0x8592:càn # 薒 0x8593:shēn # 薓 0x8594:qiáng,sè # 薔 0x8595:lián # 薕 0x8596:kē # 薖 0x8597:yuán # 薗 0x8598:dá # 薘 0x8599:tì # 薙 0x859a:tāng # 薚 0x859b:xuē # 薛 0x859c:bì # 薜 0x859d:zhān # 薝 0x859e:sūn # 薞 0x859f:xiān,liǎn # 薟 0x85a0:fán # 薠 0x85a1:dǐng # 薡 0x85a2:xiè # 薢 0x85a3:gǔ # 薣 0x85a4:xiè # 薤 0x85a5:shǔ # 薥 0x85a6:jiàn # 薦 0x85a7:hāo,kǎo # 薧 0x85a8:hōng # 薨 0x85a9:sà # 薩 0x85aa:xīn # 薪 0x85ab:xūn # 薫 0x85ac:yào # 薬 0x85ae:sǒu # 薮 0x85af:shǔ # 薯 0x85b0:xūn # 薰 0x85b1:duì # 薱 0x85b2:pín # 薲 0x85b3:yuǎn,wěi # 薳 0x85b4:níng # 薴 0x85b5:chóu,zhòu # 薵 0x85b6:mái,wō # 薶 0x85b7:rú # 薷 0x85b8:piáo # 薸 0x85b9:tái # 薹 0x85ba:jì,qí # 薺 0x85bb:zǎo # 薻 0x85bc:chén # 薼 0x85bd:zhēn # 薽 0x85be:ěr # 薾 0x85bf:nǐ # 薿 0x85c0:yíng # 藀 0x85c1:gǎo # 藁 0x85c2:cóng # 藂 0x85c3:xiāo,hào # 藃 0x85c4:qí # 藄 0x85c5:fá # 藅 0x85c6:jiǎn # 藆 0x85c7:xù,yù,xū # 藇 0x85c8:kuí # 藈 0x85c9:jiè,jí # 藉 0x85ca:biǎn # 藊 0x85cb:diào,zhuó # 藋 0x85cc:mí # 藌 0x85cd:lán # 藍 0x85ce:jìn # 藎 0x85cf:cáng,zàng # 藏 0x85d0:miǎo # 藐 0x85d1:qióng # 藑 0x85d2:qì # 藒 0x85d3:xiǎn # 藓 0x85d5:ǒu # 藕 0x85d6:xián # 藖 0x85d7:sù # 藗 0x85d8:lǘ # 藘 0x85d9:yì # 藙 0x85da:xù # 藚 0x85db:xiě # 藛 0x85dc:lí # 藜 0x85dd:yì # 藝 0x85de:lǎ # 藞 0x85df:lěi # 藟 0x85e0:jiào # 藠 0x85e1:dí # 藡 0x85e2:zhǐ # 藢 0x85e3:bēi # 藣 0x85e4:téng # 藤 0x85e5:yào # 藥 0x85e6:mò # 藦 0x85e7:huàn # 藧 0x85e8:biāo,pāo # 藨 0x85e9:fān # 藩 0x85ea:sǒu # 藪 0x85eb:tán # 藫 0x85ec:tuī # 藬 0x85ed:qióng # 藭 0x85ee:qiáo # 藮 0x85ef:wèi # 藯 0x85f0:liú,liǔ # 藰 0x85f1:huì,huí # 藱 0x85f3:gǎo # 藳 0x85f4:yùn # 藴 0x85f6:lì # 藶 0x85f7:shǔ # 藷 0x85f8:zhū,chú # 藸 0x85f9:ǎi # 藹 0x85fa:lìn # 藺 0x85fb:zǎo # 藻 0x85fc:xuān # 藼 0x85fd:qìn # 藽 0x85fe:lài # 藾 0x85ff:huò # 藿 0x8600:tuò # 蘀 0x8601:wù # 蘁 0x8602:ruǐ # 蘂 0x8603:ruǐ # 蘃 0x8604:qí # 蘄 0x8605:héng # 蘅 0x8606:lú # 蘆 0x8607:sū # 蘇 0x8608:tuí # 蘈 0x8609:máng # 蘉 0x860a:yùn # 蘊 0x860b:pín,píng # 蘋 0x860c:yù # 蘌 0x860d:xūn # 蘍 0x860e:jì # 蘎 0x860f:jiōng # 蘏 0x8610:xuān # 蘐 0x8611:mó # 蘑 0x8613:sū # 蘓 0x8614:jiōng # 蘔 0x8616:niè # 蘖 0x8617:bò # 蘗 0x8618:ráng # 蘘 0x8619:yì # 蘙 0x861a:xiǎn # 蘚 0x861b:yú # 蘛 0x861c:jú # 蘜 0x861d:liǎn # 蘝 0x861e:liǎn # 蘞 0x861f:yǐn # 蘟 0x8620:qiáng # 蘠 0x8621:yīng # 蘡 0x8622:lóng # 蘢 0x8623:tǒu # 蘣 0x8624:huā # 蘤 0x8625:yuè # 蘥 0x8626:lìng # 蘦 0x8627:qú # 蘧 0x8628:yáo # 蘨 0x8629:fán # 蘩 0x862a:mí # 蘪 0x862b:lán # 蘫 0x862c:guī # 蘬 0x862d:lán # 蘭 0x862e:jì # 蘮 0x862f:dàng # 蘯 0x8631:lèi # 蘱 0x8632:léi # 蘲 0x8633:huī # 蘳 0x8634:fēng # 蘴 0x8635:zhī # 蘵 0x8636:wèi # 蘶 0x8637:kuí # 蘷 0x8638:zhàn # 蘸 0x8639:huái # 蘹 0x863a:lí # 蘺 0x863b:jì # 蘻 0x863c:mí # 蘼 0x863d:lěi # 蘽 0x863e:huài # 蘾 0x863f:luó # 蘿 0x8640:jī # 虀 0x8641:kuí # 虁 0x8642:lù # 虂 0x8643:jiān # 虃 0x8646:léi # 虆 0x8647:quǎn # 虇 0x8648:xiāo # 虈 0x8649:yì # 虉 0x864a:luán # 虊 0x864b:mén # 虋 0x864c:biē # 虌 0x864d:hū # 虍 0x864e:hǔ # 虎 0x864f:lǔ # 虏 0x8650:nüè # 虐 0x8651:lǜ # 虑 0x8652:sī # 虒 0x8653:xiāo # 虓 0x8654:qián # 虔 0x8655:chǔ # 處 0x8656:hū # 虖 0x8657:xū # 虗 0x8658:cuó # 虘 0x8659:fú # 虙 0x865a:xū # 虚 0x865b:xū # 虛 0x865c:lǔ # 虜 0x865d:hǔ # 虝 0x865e:yú # 虞 0x865f:hào,háo # 號 0x8660:jiāo # 虠 0x8661:jù # 虡 0x8662:guó # 虢 0x8663:bào # 虣 0x8664:yán # 虤 0x8665:zhàn # 虥 0x8666:zhàn # 虦 0x8667:kuī # 虧 0x8668:bīn # 虨 0x8669:xì # 虩 0x866a:shù # 虪 0x866b:chóng # 虫 0x866c:qiú # 虬 0x866d:diāo # 虭 0x866e:jǐ # 虮 0x866f:qiú # 虯 0x8670:dīng # 虰 0x8671:shī # 虱 0x8673:jué # 虳 0x8674:zhé # 虴 0x8675:shé # 虵 0x8676:yú # 虶 0x8677:hán # 虷 0x8678:zǐ # 虸 0x8679:hóng # 虹 0x867a:huǐ,huī # 虺 0x867b:méng # 虻 0x867c:gè # 虼 0x867d:suī # 虽 0x867e:xiā,hā # 虾 0x867f:chài # 虿 0x8680:shí # 蚀 0x8681:yǐ # 蚁 0x8682:mǎ,mā,mà # 蚂 0x8683:xiǎng # 蚃 0x8684:fāng,bàng # 蚄 0x8685:è # 蚅 0x8686:bā # 蚆 0x8687:chǐ # 蚇 0x8688:qiān # 蚈 0x8689:wén # 蚉 0x868a:wén # 蚊 0x868b:ruì # 蚋 0x868c:bàng,bèng # 蚌 0x868d:pí # 蚍 0x868e:yuè # 蚎 0x868f:yuè # 蚏 0x8690:jūn # 蚐 0x8691:qí # 蚑 0x8692:tóng # 蚒 0x8693:yǐn # 蚓 0x8694:qí,zhǐ # 蚔 0x8695:cán # 蚕 0x8696:yuán,wán # 蚖 0x8697:jué,quē # 蚗 0x8698:huí # 蚘 0x8699:qín,qián # 蚙 0x869a:qí # 蚚 0x869b:zhòng # 蚛 0x869c:yá # 蚜 0x869d:háo # 蚝 0x869e:mù # 蚞 0x869f:wáng # 蚟 0x86a0:fén # 蚠 0x86a1:fén # 蚡 0x86a2:háng # 蚢 0x86a3:gōng,zhōng # 蚣 0x86a4:zǎo # 蚤 0x86a5:fù,fǔ # 蚥 0x86a6:rán # 蚦 0x86a7:jiè # 蚧 0x86a8:fú # 蚨 0x86a9:chī # 蚩 0x86aa:dǒu # 蚪 0x86ab:bào # 蚫 0x86ac:xiǎn # 蚬 0x86ad:ní # 蚭 0x86ae:dài,dé # 蚮 0x86af:qiū # 蚯 0x86b0:yóu # 蚰 0x86b1:zhà # 蚱 0x86b2:píng # 蚲 0x86b3:chí # 蚳 0x86b4:yòu # 蚴 0x86b5:kē # 蚵 0x86b6:hān # 蚶 0x86b7:jù # 蚷 0x86b8:lì # 蚸 0x86b9:fù # 蚹 0x86ba:rán # 蚺 0x86bb:zhá # 蚻 0x86bc:gǒu,qú,xù # 蚼 0x86bd:pí # 蚽 0x86be:pí,bǒ # 蚾 0x86bf:xián # 蚿 0x86c0:zhù # 蛀 0x86c1:diāo # 蛁 0x86c2:bié # 蛂 0x86c3:bīng # 蛃 0x86c4:gū # 蛄 0x86c5:zhān # 蛅 0x86c6:qū # 蛆 0x86c7:shé,yí # 蛇 0x86c8:tiě # 蛈 0x86c9:líng # 蛉 0x86ca:gǔ # 蛊 0x86cb:dàn # 蛋 0x86cc:tún # 蛌 0x86cd:yíng # 蛍 0x86ce:lì # 蛎 0x86cf:chēng # 蛏 0x86d0:qū # 蛐 0x86d1:móu # 蛑 0x86d2:gé,luò # 蛒 0x86d3:cì # 蛓 0x86d4:huí # 蛔 0x86d5:huí # 蛕 0x86d6:máng,bàng # 蛖 0x86d7:fù # 蛗 0x86d8:yáng # 蛘 0x86d9:wā # 蛙 0x86da:liè # 蛚 0x86db:zhū # 蛛 0x86dc:yī # 蛜 0x86dd:xián # 蛝 0x86de:kuò # 蛞 0x86df:jiāo # 蛟 0x86e0:lì # 蛠 0x86e1:yì,xǔ # 蛡 0x86e2:píng # 蛢 0x86e3:jié # 蛣 0x86e4:gé,há # 蛤 0x86e5:shé # 蛥 0x86e6:yí # 蛦 0x86e7:wǎng # 蛧 0x86e8:mò # 蛨 0x86e9:qióng # 蛩 0x86ea:qiè,ní # 蛪 0x86eb:guǐ # 蛫 0x86ec:qióng # 蛬 0x86ed:zhì # 蛭 0x86ee:mán # 蛮 0x86f0:zhé # 蛰 0x86f1:jiá # 蛱 0x86f2:náo # 蛲 0x86f3:sī # 蛳 0x86f4:qí # 蛴 0x86f5:xíng # 蛵 0x86f6:jiè # 蛶 0x86f7:qiú # 蛷 0x86f8:xiāo,shāo # 蛸 0x86f9:yǒng # 蛹 0x86fa:jiá # 蛺 0x86fb:tuì # 蛻 0x86fc:chē # 蛼 0x86fd:bèi # 蛽 0x86fe:é,yǐ # 蛾 0x86ff:hàn # 蛿 0x8700:shǔ # 蜀 0x8701:xuán # 蜁 0x8702:fēng # 蜂 0x8703:shèn # 蜃 0x8704:shèn # 蜄 0x8705:fǔ # 蜅 0x8706:xiǎn # 蜆 0x8707:zhé # 蜇 0x8708:wú # 蜈 0x8709:fú # 蜉 0x870a:lì # 蜊 0x870b:láng # 蜋 0x870c:bì # 蜌 0x870d:chú # 蜍 0x870e:yuān # 蜎 0x870f:yǒu # 蜏 0x8710:jié # 蜐 0x8711:dàn # 蜑 0x8712:yán # 蜒 0x8713:tíng # 蜓 0x8714:diàn # 蜔 0x8715:tuì # 蜕 0x8716:huí # 蜖 0x8717:wō # 蜗 0x8718:zhī # 蜘 0x8719:zhōng # 蜙 0x871a:fēi # 蜚 0x871b:jū # 蜛 0x871c:mì # 蜜 0x871d:qí # 蜝 0x871e:qí # 蜞 0x871f:yù # 蜟 0x8720:jùn # 蜠 0x8721:là,zhà # 蜡 0x8722:měng # 蜢 0x8723:qiāng # 蜣 0x8724:sī # 蜤 0x8725:xī # 蜥 0x8726:lún # 蜦 0x8727:lì # 蜧 0x8728:dié # 蜨 0x8729:tiáo # 蜩 0x872a:táo # 蜪 0x872b:kūn # 蜫 0x872c:hán # 蜬 0x872d:hàn # 蜭 0x872e:yù # 蜮 0x872f:bàng # 蜯 0x8730:féi # 蜰 0x8731:pí # 蜱 0x8732:wēi # 蜲 0x8733:dūn # 蜳 0x8734:yì # 蜴 0x8735:yuān # 蜵 0x8736:suò # 蜶 0x8737:quán # 蜷 0x8738:qiǎn # 蜸 0x8739:ruì # 蜹 0x873a:ní # 蜺 0x873b:qīng # 蜻 0x873c:wèi # 蜼 0x873d:liǎng # 蜽 0x873e:guǒ # 蜾 0x873f:wān # 蜿 0x8740:dōng # 蝀 0x8741:è # 蝁 0x8742:bǎn # 蝂 0x8743:dì # 蝃 0x8744:wǎng # 蝄 0x8745:cán # 蝅 0x8746:yǎng # 蝆 0x8747:yíng # 蝇 0x8748:guō # 蝈 0x8749:chán # 蝉 0x874b:là # 蝋 0x874c:kē # 蝌 0x874d:jí # 蝍 0x874e:xiē # 蝎 0x874f:tíng # 蝏 0x8750:mào # 蝐 0x8751:xū # 蝑 0x8752:mián # 蝒 0x8753:yú # 蝓 0x8754:jiē # 蝔 0x8755:shí # 蝕 0x8756:xuān # 蝖 0x8757:huáng # 蝗 0x8758:yǎn # 蝘 0x8759:biān # 蝙 0x875a:róu # 蝚 0x875b:wēi # 蝛 0x875c:fù # 蝜 0x875d:yuán # 蝝 0x875e:mèi # 蝞 0x875f:wèi # 蝟 0x8760:fú # 蝠 0x8761:rú,ruăn # 蝡 0x8762:xié # 蝢 0x8763:yóu # 蝣 0x8764:qiú,yóu # 蝤 0x8765:máo # 蝥 0x8766:xiā,hā # 蝦 0x8767:yīng # 蝧 0x8768:shī # 蝨 0x8769:chóng # 蝩 0x876a:tāng # 蝪 0x876b:zhū # 蝫 0x876c:zōng # 蝬 0x876d:dì # 蝭 0x876e:fù # 蝮 0x876f:yuán # 蝯 0x8770:kuí # 蝰 0x8771:méng # 蝱 0x8772:là # 蝲 0x8773:dài # 蝳 0x8774:hú # 蝴 0x8775:qiū # 蝵 0x8776:dié # 蝶 0x8777:lì # 蝷 0x8778:wō # 蝸 0x8779:yūn # 蝹 0x877a:qǔ # 蝺 0x877b:nǎn # 蝻 0x877c:lóu # 蝼 0x877d:chūn # 蝽 0x877e:róng # 蝾 0x877f:yíng # 蝿 0x8780:jiāng # 螀 0x8782:láng # 螂 0x8783:páng # 螃 0x8784:sī # 螄 0x8785:xī # 螅 0x8786:cì # 螆 0x8787:xī,qī # 螇 0x8788:yuán # 螈 0x8789:wēng # 螉 0x878a:lián # 螊 0x878b:sōu # 螋 0x878c:bān # 螌 0x878d:róng # 融 0x878e:róng # 螎 0x878f:jí # 螏 0x8790:wū # 螐 0x8791:xiù # 螑 0x8792:hàn # 螒 0x8793:qín # 螓 0x8794:yí # 螔 0x8795:bī,pí # 螕 0x8796:huá # 螖 0x8797:táng # 螗 0x8798:yǐ # 螘 0x8799:dù # 螙 0x879a:nài,něng # 螚 0x879b:hé,xiá # 螛 0x879c:hú # 螜 0x879d:guì,huǐ # 螝 0x879e:mǎ,mā,mà # 螞 0x879f:míng # 螟 0x87a0:yì # 螠 0x87a1:wén # 螡 0x87a2:yíng # 螢 0x87a3:téng # 螣 0x87a4:zhōng # 螤 0x87a5:cāng # 螥 0x87a8:mǎn # 螨 0x87aa:shāng # 螪 0x87ab:shì,zhē # 螫 0x87ac:cáo # 螬 0x87ad:chī # 螭 0x87ae:dì # 螮 0x87af:áo # 螯 0x87b0:lù # 螰 0x87b1:wèi # 螱 0x87b2:dié,zhì # 螲 0x87b3:táng # 螳 0x87b4:chén # 螴 0x87b5:piāo # 螵 0x87b6:qú,jù # 螶 0x87b7:pí # 螷 0x87b8:yú # 螸 0x87b9:chán,jiàn # 螹 0x87ba:luó # 螺 0x87bb:lóu # 螻 0x87bc:qǐn # 螼 0x87bd:zhōng # 螽 0x87be:yǐn # 螾 0x87bf:jiāng # 螿 0x87c0:shuài # 蟀 0x87c1:wén # 蟁 0x87c2:xiāo # 蟂 0x87c3:wàn # 蟃 0x87c4:zhé # 蟄 0x87c5:zhè # 蟅 0x87c6:má,mò # 蟆 0x87c7:má # 蟇 0x87c8:guō # 蟈 0x87c9:liú # 蟉 0x87ca:máo # 蟊 0x87cb:xī # 蟋 0x87cc:cōng # 蟌 0x87cd:lí # 蟍 0x87ce:mǎn # 蟎 0x87cf:xiāo # 蟏 0x87d1:zhāng # 蟑 0x87d2:mǎng,měng # 蟒 0x87d3:xiàng # 蟓 0x87d4:mò # 蟔 0x87d5:zuī # 蟕 0x87d6:sī # 蟖 0x87d7:qiū # 蟗 0x87d8:tè # 蟘 0x87d9:zhí # 蟙 0x87da:péng # 蟚 0x87db:péng # 蟛 0x87dc:jiǎo # 蟜 0x87dd:qú # 蟝 0x87de:biē,bié # 蟞 0x87df:liáo # 蟟 0x87e0:pán # 蟠 0x87e1:guǐ # 蟡 0x87e2:xǐ # 蟢 0x87e3:jǐ # 蟣 0x87e4:zhuān # 蟤 0x87e5:huáng # 蟥 0x87e6:fèi,bēn # 蟦 0x87e7:láo,liáo # 蟧 0x87e8:jué # 蟨 0x87e9:jué # 蟩 0x87ea:huì # 蟪 0x87eb:yín,xún # 蟫 0x87ec:chán # 蟬 0x87ed:jiāo # 蟭 0x87ee:shàn # 蟮 0x87ef:náo # 蟯 0x87f0:xiāo # 蟰 0x87f1:wú # 蟱 0x87f2:chóng # 蟲 0x87f3:xún # 蟳 0x87f4:sī # 蟴 0x87f6:chēng # 蟶 0x87f7:dāng # 蟷 0x87f8:lí # 蟸 0x87f9:xiè # 蟹 0x87fa:shàn # 蟺 0x87fb:yǐ # 蟻 0x87fc:jǐng # 蟼 0x87fd:dá # 蟽 0x87fe:chán # 蟾 0x87ff:qì # 蟿 0x8800:cī # 蠀 0x8801:xiǎng # 蠁 0x8802:shè # 蠂 0x8803:luǒ # 蠃 0x8804:qín # 蠄 0x8805:yíng # 蠅 0x8806:chài # 蠆 0x8807:lì # 蠇 0x8808:zéi # 蠈 0x8809:xuān # 蠉 0x880a:lián # 蠊 0x880b:zhú # 蠋 0x880c:zé # 蠌 0x880d:xiē # 蠍 0x880e:mǎng # 蠎 0x880f:xiè # 蠏 0x8810:qí # 蠐 0x8811:róng # 蠑 0x8812:jiǎn # 蠒 0x8813:měng # 蠓 0x8814:háo # 蠔 0x8815:rú # 蠕 0x8816:huò # 蠖 0x8817:zhuó # 蠗 0x8818:jié # 蠘 0x8819:pín # 蠙 0x881a:hē # 蠚 0x881b:miè # 蠛 0x881c:fán # 蠜 0x881d:lěi # 蠝 0x881e:jié # 蠞 0x881f:là # 蠟 0x8820:mǐn # 蠠 0x8821:lǐ # 蠡 0x8822:chǔn # 蠢 0x8823:lì # 蠣 0x8824:qiū # 蠤 0x8825:niè # 蠥 0x8826:lú # 蠦 0x8827:dù # 蠧 0x8828:xiāo # 蠨 0x8829:zhū # 蠩 0x882a:lóng # 蠪 0x882b:lí # 蠫 0x882c:lóng # 蠬 0x882d:fēng # 蠭 0x882e:yē # 蠮 0x882f:pí # 蠯 0x8830:náng # 蠰 0x8831:gǔ # 蠱 0x8832:juān # 蠲 0x8833:yīng # 蠳 0x8835:xī # 蠵 0x8836:cán # 蠶 0x8837:qú # 蠷 0x8838:quán # 蠸 0x8839:dù # 蠹 0x883a:cán # 蠺 0x883b:mán # 蠻 0x883c:qú # 蠼 0x883d:jié # 蠽 0x883e:zhú # 蠾 0x883f:zhuó # 蠿 0x8840:xiě,xuè # 血 0x8841:huāng # 衁 0x8842:nǜ # 衂 0x8843:pēi # 衃 0x8844:nǜ # 衄 0x8845:xìn # 衅 0x8846:zhòng # 衆 0x8847:mài # 衇 0x8848:ěr # 衈 0x8849:kè # 衉 0x884a:miè # 衊 0x884b:xì # 衋 0x884c:háng,xíng,héng,hàng # 行 0x884d:yǎn # 衍 0x884e:kàn # 衎 0x884f:yuàn # 衏 0x8851:líng # 衑 0x8852:xuàn # 衒 0x8853:shù # 術 0x8854:xián # 衔 0x8855:tòng # 衕 0x8856:xiàng # 衖 0x8857:jiē # 街 0x8858:xián # 衘 0x8859:yá # 衙 0x885a:hú # 衚 0x885b:wèi # 衛 0x885c:dào # 衜 0x885d:chōng # 衝 0x885e:wèi # 衞 0x885f:dào # 衟 0x8860:zhūn # 衠 0x8861:héng # 衡 0x8862:qú # 衢 0x8863:yī # 衣 0x8865:bǔ # 补 0x8866:gǎn # 衦 0x8867:yú # 衧 0x8868:biǎo # 表 0x8869:chà # 衩 0x886a:yì # 衪 0x886b:shān # 衫 0x886c:chèn # 衬 0x886d:fū # 衭 0x886e:gǔn # 衮 0x886f:fēn # 衯 0x8870:shuāi,cuī # 衰 0x8871:jié # 衱 0x8872:nà # 衲 0x8873:zhōng # 衳 0x8874:dǎn # 衴 0x8875:rì # 衵 0x8876:zhòng # 衶 0x8877:zhōng # 衷 0x8878:jiè # 衸 0x8879:zhǐ # 衹 0x887a:xié # 衺 0x887b:rán # 衻 0x887c:zhī # 衼 0x887d:rèn # 衽 0x887e:qīn # 衾 0x887f:jīn # 衿 0x8880:jūn # 袀 0x8881:yuán # 袁 0x8882:mèi # 袂 0x8883:chài # 袃 0x8884:ǎo # 袄 0x8885:niǎo # 袅 0x8886:huī # 袆 0x8887:rán # 袇 0x8888:jiā # 袈 0x8889:tuó,tuō # 袉 0x888a:lǐng,líng # 袊 0x888b:dài # 袋 0x888c:bào,páo,pào # 袌 0x888d:páo # 袍 0x888e:yào # 袎 0x888f:zuò # 袏 0x8890:bì # 袐 0x8891:shào # 袑 0x8892:tǎn # 袒 0x8893:jù,jiē # 袓 0x8894:hè,kè # 袔 0x8895:xué # 袕 0x8896:xiù # 袖 0x8897:zhěn # 袗 0x8898:yí,yì # 袘 0x8899:pà # 袙 0x889a:fú # 袚 0x889b:dī # 袛 0x889c:wà # 袜 0x889d:fù # 袝 0x889e:gǔn # 袞 0x889f:zhì # 袟 0x88a0:zhì # 袠 0x88a1:rán # 袡 0x88a2:pàn # 袢 0x88a3:yì # 袣 0x88a4:mào # 袤 0x88a6:nà,jué # 袦 0x88a7:gōu # 袧 0x88a8:xuàn # 袨 0x88a9:zhé # 袩 0x88aa:qū # 袪 0x88ab:bèi,pī # 被 0x88ac:yù # 袬 0x88ad:xí # 袭 0x88af:bó # 袯 0x88b1:fú # 袱 0x88b2:chǐ,nuǒ # 袲 0x88b3:chǐ,qǐ,duǒ,nuǒ # 袳 0x88b4:kù # 袴 0x88b5:rèn # 袵 0x88b6:péng # 袶 0x88b7:jiá,jié,qiā # 袷 0x88b8:jiàn,zùn # 袸 0x88b9:bó,mò # 袹 0x88ba:jié # 袺 0x88bb:ér # 袻 0x88bc:gē # 袼 0x88bd:rú # 袽 0x88be:zhū # 袾 0x88bf:guī,guà # 袿 0x88c0:yīn # 裀 0x88c1:cái # 裁 0x88c2:liè,liě # 裂 0x88c5:zhuāng # 装 0x88c6:dāng # 裆 0x88c8:kūn # 裈 0x88c9:kèn # 裉 0x88ca:niǎo # 裊 0x88cb:shù # 裋 0x88cc:jiá # 裌 0x88cd:kǔn # 裍 0x88ce:chéng,chěng # 裎 0x88cf:lǐ # 裏 0x88d0:juān # 裐 0x88d1:shēn # 裑 0x88d2:póu # 裒 0x88d3:gé,jiē # 裓 0x88d4:yì # 裔 0x88d5:yù # 裕 0x88d6:zhěn # 裖 0x88d7:liú # 裗 0x88d8:qiú # 裘 0x88d9:qún # 裙 0x88da:jì # 裚 0x88db:yì # 裛 0x88dc:bǔ # 補 0x88dd:zhuāng # 裝 0x88de:shuì # 裞 0x88df:shā # 裟 0x88e0:qún # 裠 0x88e1:lǐ # 裡 0x88e2:lián # 裢 0x88e3:liǎn # 裣 0x88e4:kù # 裤 0x88e5:jiǎn # 裥 0x88e6:bāo # 裦 0x88e7:chān # 裧 0x88e8:bì,pí # 裨 0x88e9:kūn # 裩 0x88ea:táo # 裪 0x88eb:yuàn # 裫 0x88ec:líng # 裬 0x88ed:chǐ # 裭 0x88ee:chāng # 裮 0x88ef:chóu,dāo # 裯 0x88f0:duō # 裰 0x88f1:biǎo # 裱 0x88f2:liǎng # 裲 0x88f3:cháng,shang # 裳 0x88f4:péi # 裴 0x88f5:péi # 裵 0x88f6:fēi # 裶 0x88f7:yuān,gǔn # 裷 0x88f8:luǒ # 裸 0x88f9:guǒ # 裹 0x88fa:yǎn,ān # 裺 0x88fb:dú # 裻 0x88fc:xī,tì # 裼 0x88fd:zhì # 製 0x88fe:jū # 裾 0x88ff:yǐ # 裿 0x8900:qí # 褀 0x8901:guǒ # 褁 0x8902:guà # 褂 0x8903:kèn # 褃 0x8905:tì # 褅 0x8906:tí # 褆 0x8907:fù # 複 0x8908:chóng # 褈 0x8909:xiè # 褉 0x890a:biǎn # 褊 0x890b:dié # 褋 0x890c:kūn # 褌 0x890d:duān # 褍 0x890e:xiù,yòu # 褎 0x890f:xiù # 褏 0x8910:hè # 褐 0x8911:yuàn # 褑 0x8912:bāo # 褒 0x8913:bǎo # 褓 0x8914:fù,fú # 褔 0x8915:yú # 褕 0x8916:tuàn # 褖 0x8917:yǎn # 褗 0x8918:huī # 褘 0x8919:bèi # 褙 0x891a:zhǔ,chǔ # 褚 0x891b:lǚ # 褛 0x891e:yùn # 褞 0x891f:tā # 褟 0x8920:gōu # 褠 0x8921:dā # 褡 0x8922:huái # 褢 0x8923:róng # 褣 0x8924:yuán # 褤 0x8925:rù # 褥 0x8926:nài # 褦 0x8927:jiǒng # 褧 0x8928:suǒ # 褨 0x8929:bān # 褩 0x892a:tuì,tùn # 褪 0x892b:chǐ # 褫 0x892c:sǎng # 褬 0x892d:niǎo # 褭 0x892e:yīng # 褮 0x892f:jiè # 褯 0x8930:qiān # 褰 0x8931:huái # 褱 0x8932:kù # 褲 0x8933:lián # 褳 0x8934:lán # 褴 0x8935:lí # 褵 0x8936:zhě # 褶 0x8937:shī # 褷 0x8938:lǚ # 褸 0x8939:yì # 褹 0x893a:diē # 褺 0x893b:xiè # 褻 0x893c:xiān # 褼 0x893d:wèi # 褽 0x893e:biǎo # 褾 0x893f:cáo # 褿 0x8940:jì # 襀 0x8941:qiǎng # 襁 0x8942:sēn # 襂 0x8943:bāo # 襃 0x8944:xiāng # 襄 0x8946:fú # 襆 0x8947:jiǎn # 襇 0x8948:zhuàn # 襈 0x8949:jiǎn # 襉 0x894a:cuì # 襊 0x894b:jí # 襋 0x894c:dān # 襌 0x894d:zá # 襍 0x894e:fán # 襎 0x894f:bó # 襏 0x8950:xiàng # 襐 0x8951:xín # 襑 0x8952:bié # 襒 0x8953:ráo # 襓 0x8954:mǎn # 襔 0x8955:lán # 襕 0x8956:ǎo # 襖 0x8957:zé # 襗 0x8958:guì # 襘 0x8959:cào # 襙 0x895a:suì # 襚 0x895b:nóng # 襛 0x895c:chān # 襜 0x895d:liǎn # 襝 0x895e:bì # 襞 0x895f:jīn # 襟 0x8960:dāng # 襠 0x8961:shǔ # 襡 0x8962:tǎn # 襢 0x8963:bì # 襣 0x8964:lán # 襤 0x8965:fú # 襥 0x8966:rú # 襦 0x8967:zhǐ # 襧 0x8969:shǔ # 襩 0x896a:wà # 襪 0x896b:shì # 襫 0x896c:bǎi # 襬 0x896d:xié # 襭 0x896e:bó # 襮 0x896f:chèn # 襯 0x8970:lǎi # 襰 0x8971:lóng # 襱 0x8972:xí # 襲 0x8973:xiān # 襳 0x8974:lán # 襴 0x8975:zhě # 襵 0x8976:dài # 襶 0x8978:zàn # 襸 0x8979:shī # 襹 0x897a:jiǎn # 襺 0x897b:pàn # 襻 0x897c:yì # 襼 0x897e:yà # 襾 0x897f:xī # 西 0x8980:yà # 覀 0x8981:yào,yāo # 要 0x8982:fěng # 覂 0x8983:tán,qín # 覃 0x8985:fiào # 覅 0x8986:fù # 覆 0x8987:bà # 覇 0x8988:hé # 覈 0x8989:jī # 覉 0x898a:jī # 覊 0x898b:jiàn,xiàn # 見 0x898c:guān,guàn # 覌 0x898d:biàn # 覍 0x898e:yàn # 覎 0x898f:guī # 規 0x8990:jué,jiào # 覐 0x8991:piǎn # 覑 0x8992:mào # 覒 0x8993:mì # 覓 0x8994:mì # 覔 0x8995:piē,miè # 覕 0x8996:shì # 視 0x8997:sì # 覗 0x8998:chān # 覘 0x8999:zhěn # 覙 0x899a:jué,jiào # 覚 0x899b:mì # 覛 0x899c:tiào # 覜 0x899d:lián # 覝 0x899e:yào # 覞 0x899f:zhì # 覟 0x89a0:jūn # 覠 0x89a1:xī # 覡 0x89a2:shǎn # 覢 0x89a3:wēi # 覣 0x89a4:xì # 覤 0x89a5:tiǎn # 覥 0x89a6:yú # 覦 0x89a7:lǎn # 覧 0x89a8:è # 覨 0x89a9:dǔ # 覩 0x89aa:qīn,qìng # 親 0x89ab:pǎng # 覫 0x89ac:jì # 覬 0x89ad:míng # 覭 0x89ae:yíng,yǐng # 覮 0x89af:gòu # 覯 0x89b0:qū,qù # 覰 0x89b1:zhàn,zhān # 覱 0x89b2:jìn # 覲 0x89b3:guān,guàn # 観 0x89b4:dèng # 覴 0x89b5:jiàn,biǎn # 覵 0x89b6:luó,luǎn # 覶 0x89b7:qù,qū # 覷 0x89b8:jiàn # 覸 0x89b9:wéi # 覹 0x89ba:jué,jiào # 覺 0x89bb:qù,qū # 覻 0x89bc:luó # 覼 0x89bd:lǎn # 覽 0x89be:shěn # 覾 0x89bf:dí # 覿 0x89c0:guān,guàn # 觀 0x89c1:jiàn,xiàn # 见 0x89c2:guān,guàn # 观 0x89c3:yàn # 觃 0x89c4:guī # 规 0x89c5:mì # 觅 0x89c6:shì # 视 0x89c7:chān # 觇 0x89c8:lǎn # 览 0x89c9:jué,jiào # 觉 0x89ca:jì # 觊 0x89cb:xí # 觋 0x89cc:dí # 觌 0x89cd:tiǎn # 觍 0x89ce:yú # 觎 0x89cf:gòu # 觏 0x89d0:jìn # 觐 0x89d1:qù,qū # 觑 0x89d2:jiǎo,jué # 角 0x89d3:qiú # 觓 0x89d4:jīn # 觔 0x89d5:cū # 觕 0x89d6:jué # 觖 0x89d7:zhì # 觗 0x89d8:chào # 觘 0x89d9:jí # 觙 0x89da:gū # 觚 0x89db:dàn # 觛 0x89dc:zī,zuǐ # 觜 0x89dd:dǐ # 觝 0x89de:shāng # 觞 0x89df:huà,xiè # 觟 0x89e0:quán # 觠 0x89e1:gé # 觡 0x89e2:shì # 觢 0x89e3:jiě,jiè,xiè # 解 0x89e4:guǐ # 觤 0x89e5:gōng # 觥 0x89e6:chù # 触 0x89e7:jiě,jiè,xiè # 觧 0x89e8:hùn # 觨 0x89e9:qiú # 觩 0x89ea:xīng # 觪 0x89eb:sù # 觫 0x89ec:ní # 觬 0x89ed:jī,qí # 觭 0x89ee:jué # 觮 0x89ef:zhì # 觯 0x89f0:zhā # 觰 0x89f1:bì # 觱 0x89f2:xīng # 觲 0x89f3:hú # 觳 0x89f4:shāng # 觴 0x89f5:gōng # 觵 0x89f6:zhì # 觶 0x89f7:xué,hù # 觷 0x89f8:chù # 觸 0x89f9:xī # 觹 0x89fa:yí # 觺 0x89fb:lì,lù # 觻 0x89fc:jué # 觼 0x89fd:xī # 觽 0x89fe:yàn # 觾 0x89ff:xī # 觿 0x8a00:yán # 言 0x8a02:dìng # 訂 0x8a03:fù # 訃 0x8a04:qiú # 訄 0x8a05:qiú # 訅 0x8a06:jiào # 訆 0x8a07:hōng # 訇 0x8a08:jì # 計 0x8a09:fàn # 訉 0x8a0a:xùn # 訊 0x8a0b:diào # 訋 0x8a0c:hòng # 訌 0x8a0d:chài,chā,chà # 訍 0x8a0e:tǎo # 討 0x8a0f:xū # 訏 0x8a10:jié # 訐 0x8a11:dàn,yí # 訑 0x8a12:rèn # 訒 0x8a13:xùn # 訓 0x8a14:yín # 訔 0x8a15:shàn # 訕 0x8a16:qì # 訖 0x8a17:tuō # 託 0x8a18:jì # 記 0x8a19:xùn # 訙 0x8a1a:yín # 訚 0x8a1b:é # 訛 0x8a1c:fēn # 訜 0x8a1d:yà # 訝 0x8a1e:yāo # 訞 0x8a1f:sòng # 訟 0x8a20:shěn # 訠 0x8a21:yín # 訡 0x8a22:xīn # 訢 0x8a23:jué # 訣 0x8a24:xiáo,ná # 訤 0x8a25:nè # 訥 0x8a26:chén # 訦 0x8a27:yóu # 訧 0x8a28:zhǐ # 訨 0x8a29:xiōng # 訩 0x8a2a:fǎng # 訪 0x8a2b:xìn # 訫 0x8a2c:chāo # 訬 0x8a2d:shè # 設 0x8a2e:yán # 訮 0x8a2f:sǎ # 訯 0x8a30:zhùn # 訰 0x8a31:xū # 許 0x8a32:yì # 訲 0x8a33:yì # 訳 0x8a34:sù # 訴 0x8a35:chī # 訵 0x8a36:hē # 訶 0x8a37:shēn # 訷 0x8a38:hé # 訸 0x8a39:xù # 訹 0x8a3a:zhěn # 診 0x8a3b:zhù # 註 0x8a3c:zhèng # 証 0x8a3d:gòu # 訽 0x8a3e:zī # 訾 0x8a3f:zǐ # 訿 0x8a40:zhān # 詀 0x8a41:gǔ # 詁 0x8a42:fù # 詂 0x8a43:jiǎn # 詃 0x8a44:dié # 詄 0x8a45:líng # 詅 0x8a46:dǐ # 詆 0x8a47:yàng # 詇 0x8a48:lì # 詈 0x8a49:náo # 詉 0x8a4a:pàn # 詊 0x8a4b:zhòu # 詋 0x8a4c:gàn # 詌 0x8a4d:yì # 詍 0x8a4e:jù # 詎 0x8a4f:yào # 詏 0x8a50:zhà # 詐 0x8a51:tuó # 詑 0x8a52:yí,dài # 詒 0x8a53:qǔ # 詓 0x8a54:zhào # 詔 0x8a55:píng # 評 0x8a56:bì # 詖 0x8a57:xiòng # 詗 0x8a58:qū # 詘 0x8a59:bá # 詙 0x8a5a:dá # 詚 0x8a5b:zǔ # 詛 0x8a5c:tāo # 詜 0x8a5d:zhǔ # 詝 0x8a5e:cí # 詞 0x8a5f:zhé # 詟 0x8a60:yǒng # 詠 0x8a61:xǔ # 詡 0x8a62:xún # 詢 0x8a63:yì # 詣 0x8a64:huǎng # 詤 0x8a65:hé # 詥 0x8a66:shì # 試 0x8a67:chá # 詧 0x8a68:xiào # 詨 0x8a69:shī # 詩 0x8a6a:hěn # 詪 0x8a6b:chà # 詫 0x8a6c:gòu # 詬 0x8a6d:guǐ # 詭 0x8a6e:quán # 詮 0x8a6f:huì # 詯 0x8a70:jié # 詰 0x8a71:huà # 話 0x8a72:gāi # 該 0x8a73:xiáng # 詳 0x8a74:wēi # 詴 0x8a75:shēn # 詵 0x8a76:chóu # 詶 0x8a77:tóng # 詷 0x8a78:mí # 詸 0x8a79:zhān # 詹 0x8a7a:míng # 詺 0x8a7b:luò # 詻 0x8a7c:huī # 詼 0x8a7d:yán # 詽 0x8a7e:xiōng # 詾 0x8a7f:guà # 詿 0x8a80:èr # 誀 0x8a81:bìng # 誁 0x8a82:tiǎo,diào # 誂 0x8a83:yí,chǐ,chì # 誃 0x8a84:lěi # 誄 0x8a85:zhū # 誅 0x8a86:kuāng # 誆 0x8a87:kuā,kuà # 誇 0x8a88:wū # 誈 0x8a89:yù # 誉 0x8a8a:téng # 誊 0x8a8b:jì # 誋 0x8a8c:zhì # 誌 0x8a8d:rèn # 認 0x8a8e:cù # 誎 0x8a8f:lǎng,làng # 誏 0x8a90:é # 誐 0x8a91:kuáng # 誑 0x8a92:ēi,éi,ěi,èi,xī # 誒 0x8a93:shì # 誓 0x8a94:tǐng # 誔 0x8a95:dàn # 誕 0x8a96:bèi,bó # 誖 0x8a97:chán # 誗 0x8a98:yòu # 誘 0x8a99:kēng # 誙 0x8a9a:qiào # 誚 0x8a9b:qīn # 誛 0x8a9c:shuà # 誜 0x8a9d:ān # 誝 0x8a9e:yǔ,yù # 語 0x8a9f:xiào # 誟 0x8aa0:chéng # 誠 0x8aa1:jiè # 誡 0x8aa2:xiàn # 誢 0x8aa3:wū # 誣 0x8aa4:wù # 誤 0x8aa5:gào # 誥 0x8aa6:sòng # 誦 0x8aa7:bū # 誧 0x8aa8:huì # 誨 0x8aa9:jìng # 誩 0x8aaa:shuō,shuì,yuè # 說 0x8aab:zhèn # 誫 0x8aac:shuō,shuì,yuè # 説 0x8aad:dú # 読 0x8aaf:chàng # 誯 0x8ab0:shuí,shéi # 誰 0x8ab1:jié # 誱 0x8ab2:kè # 課 0x8ab3:qū,juè # 誳 0x8ab4:cóng # 誴 0x8ab5:xiáo # 誵 0x8ab6:suì # 誶 0x8ab7:wǎng # 誷 0x8ab8:xián # 誸 0x8ab9:fěi # 誹 0x8aba:chī,lài # 誺 0x8abb:tà # 誻 0x8abc:yì # 誼 0x8abd:nì,ná # 誽 0x8abe:yín # 誾 0x8abf:diào,tiáo # 調 0x8ac0:pǐ,bēi # 諀 0x8ac1:zhuó # 諁 0x8ac2:chǎn # 諂 0x8ac3:chēn # 諃 0x8ac4:zhūn # 諄 0x8ac5:jì,jī # 諅 0x8ac6:qī # 諆 0x8ac7:tán # 談 0x8ac8:zhuì # 諈 0x8ac9:wěi # 諉 0x8aca:jū # 諊 0x8acb:qǐng # 請 0x8acc:dǒng # 諌 0x8acd:zhèng # 諍 0x8ace:zé,zuò,zhǎ,cuò # 諎 0x8acf:zōu # 諏 0x8ad0:qiān # 諐 0x8ad1:zhuó # 諑 0x8ad2:liàng # 諒 0x8ad3:jiàn # 諓 0x8ad4:chù,jí # 諔 0x8ad5:xià,háo # 諕 0x8ad6:lùn,lún # 論 0x8ad7:shěn # 諗 0x8ad8:biǎo # 諘 0x8ad9:huà # 諙 0x8ada:biàn # 諚 0x8adb:yú # 諛 0x8adc:dié # 諜 0x8add:xū # 諝 0x8ade:piǎn # 諞 0x8adf:shì,dì # 諟 0x8ae0:xuān # 諠 0x8ae1:shì # 諡 0x8ae2:hùn # 諢 0x8ae3:huà,guā # 諣 0x8ae4:è # 諤 0x8ae5:zhòng # 諥 0x8ae6:dì # 諦 0x8ae7:xié # 諧 0x8ae8:fú # 諨 0x8ae9:pǔ # 諩 0x8aea:tíng # 諪 0x8aeb:jiàn # 諫 0x8aec:qǐ # 諬 0x8aed:yù # 諭 0x8aee:zī # 諮 0x8aef:zhuān # 諯 0x8af0:xǐ,shāi,āi # 諰 0x8af1:huì # 諱 0x8af2:yīn # 諲 0x8af3:ān # 諳 0x8af4:xián # 諴 0x8af5:nán,nàn # 諵 0x8af6:chén # 諶 0x8af7:fěng # 諷 0x8af8:zhū # 諸 0x8af9:yáng # 諹 0x8afa:yàn # 諺 0x8afb:huáng # 諻 0x8afc:xuān # 諼 0x8afd:gé # 諽 0x8afe:nuò # 諾 0x8aff:xǔ # 諿 0x8b00:móu # 謀 0x8b01:yè # 謁 0x8b02:wèi # 謂 0x8b04:téng # 謄 0x8b05:zhōu # 謅 0x8b06:shàn # 謆 0x8b07:jiǎn # 謇 0x8b08:bó # 謈 0x8b0a:huǎng # 謊 0x8b0b:huò # 謋 0x8b0c:gē # 謌 0x8b0d:yíng # 謍 0x8b0e:mí # 謎 0x8b0f:xiǎo # 謏 0x8b10:mì # 謐 0x8b11:xǐ # 謑 0x8b12:qiāng # 謒 0x8b13:chēn # 謓 0x8b14:xuè # 謔 0x8b15:tí # 謕 0x8b16:sù # 謖 0x8b17:bàng # 謗 0x8b18:chí # 謘 0x8b19:qiān # 謙 0x8b1a:shì # 謚 0x8b1b:jiǎng # 講 0x8b1c:yuán # 謜 0x8b1d:xiè # 謝 0x8b1e:hè # 謞 0x8b1f:tāo # 謟 0x8b20:yáo # 謠 0x8b21:yáo # 謡 0x8b23:yú # 謣 0x8b24:biāo # 謤 0x8b25:còng # 謥 0x8b26:qǐng # 謦 0x8b27:lí # 謧 0x8b28:mó # 謨 0x8b29:mó # 謩 0x8b2a:shāng # 謪 0x8b2b:zhé # 謫 0x8b2c:miù # 謬 0x8b2d:jiǎn # 謭 0x8b2e:zé # 謮 0x8b2f:jiē # 謯 0x8b30:lián # 謰 0x8b31:lóu # 謱 0x8b32:càn # 謲 0x8b33:ōu # 謳 0x8b34:gùn # 謴 0x8b35:xí # 謵 0x8b36:zhuó # 謶 0x8b37:áo # 謷 0x8b38:áo # 謸 0x8b39:jǐn # 謹 0x8b3a:zhé # 謺 0x8b3b:yí # 謻 0x8b3c:hū # 謼 0x8b3d:jiàng # 謽 0x8b3e:mán # 謾 0x8b3f:cháo # 謿 0x8b40:hàn # 譀 0x8b41:huá # 譁 0x8b42:chǎn # 譂 0x8b43:xū # 譃 0x8b44:zēng # 譄 0x8b45:sè # 譅 0x8b46:xī # 譆 0x8b47:zhā # 譇 0x8b48:duì # 譈 0x8b49:zhèng # 證 0x8b4a:náo # 譊 0x8b4b:lán # 譋 0x8b4c:é # 譌 0x8b4d:yīng # 譍 0x8b4e:jué # 譎 0x8b4f:jī # 譏 0x8b50:zǔn # 譐 0x8b51:jiǎo # 譑 0x8b52:bò # 譒 0x8b53:huì # 譓 0x8b54:zhuàn # 譔 0x8b55:wú # 譕 0x8b56:zèn # 譖 0x8b57:zhá # 譗 0x8b58:shí,zhì # 識 0x8b59:qiáo # 譙 0x8b5a:tán # 譚 0x8b5b:jiàn # 譛 0x8b5c:pǔ # 譜 0x8b5d:shéng # 譝 0x8b5e:xuān # 譞 0x8b5f:zào # 譟 0x8b60:tán # 譠 0x8b61:dǎng # 譡 0x8b62:suì # 譢 0x8b63:xiǎn # 譣 0x8b64:jī # 譤 0x8b65:jiào # 譥 0x8b66:jǐng # 警 0x8b67:zhàn # 譧 0x8b68:nóng # 譨 0x8b69:yī # 譩 0x8b6a:ǎi # 譪 0x8b6b:zhān # 譫 0x8b6c:pì # 譬 0x8b6d:huǐ # 譭 0x8b6e:huà # 譮 0x8b6f:yì # 譯 0x8b70:yì # 議 0x8b71:shàn # 譱 0x8b72:ràng # 譲 0x8b73:ròu # 譳 0x8b74:qiǎn # 譴 0x8b75:duì # 譵 0x8b76:tà # 譶 0x8b77:hù # 護 0x8b78:zhōu # 譸 0x8b79:háo # 譹 0x8b7a:ài # 譺 0x8b7b:yīng # 譻 0x8b7c:jiān # 譼 0x8b7d:yù # 譽 0x8b7e:jiǎn # 譾 0x8b7f:huì # 譿 0x8b80:dú # 讀 0x8b81:zhé # 讁 0x8b82:juàn,xuān # 讂 0x8b83:zàn # 讃 0x8b84:lěi # 讄 0x8b85:shěn # 讅 0x8b86:wèi # 讆 0x8b87:chǎn # 讇 0x8b88:lì # 讈 0x8b89:yí,tuī # 讉 0x8b8a:biàn # 變 0x8b8b:zhé # 讋 0x8b8c:yàn # 讌 0x8b8d:è # 讍 0x8b8e:chóu # 讎 0x8b8f:wèi # 讏 0x8b90:chóu # 讐 0x8b91:yào # 讑 0x8b92:chán # 讒 0x8b93:ràng # 讓 0x8b94:yǐn # 讔 0x8b95:lán # 讕 0x8b96:chèn # 讖 0x8b97:xié # 讗 0x8b98:niè # 讘 0x8b99:huān # 讙 0x8b9a:zàn # 讚 0x8b9b:yì # 讛 0x8b9c:dǎng # 讜 0x8b9d:zhán # 讝 0x8b9e:yàn # 讞 0x8b9f:dú # 讟 0x8ba0:yán # 讠 0x8ba1:jì # 计 0x8ba2:dìng # 订 0x8ba3:fù # 讣 0x8ba4:rèn # 认 0x8ba5:jī # 讥 0x8ba6:jié # 讦 0x8ba7:hòng # 讧 0x8ba8:tǎo # 讨 0x8ba9:ràng # 让 0x8baa:shàn # 讪 0x8bab:qì # 讫 0x8bac:tuō # 讬 0x8bad:xùn # 训 0x8bae:yì # 议 0x8baf:xùn # 讯 0x8bb0:jì # 记 0x8bb1:rèn # 讱 0x8bb2:jiǎng # 讲 0x8bb3:huì # 讳 0x8bb4:ōu # 讴 0x8bb5:jù # 讵 0x8bb6:yà # 讶 0x8bb7:nè # 讷 0x8bb8:xǔ,hǔ # 许 0x8bb9:é # 讹 0x8bba:lùn,lún # 论 0x8bbb:xiōng # 讻 0x8bbc:sòng # 讼 0x8bbd:fěng # 讽 0x8bbe:shè # 设 0x8bbf:fǎng # 访 0x8bc0:jué # 诀 0x8bc1:zhèng # 证 0x8bc2:gǔ # 诂 0x8bc3:hē # 诃 0x8bc4:píng # 评 0x8bc5:zǔ # 诅 0x8bc6:shí,zhì # 识 0x8bc7:xiòng # 诇 0x8bc8:zhà # 诈 0x8bc9:sù # 诉 0x8bca:zhěn # 诊 0x8bcb:dǐ # 诋 0x8bcc:zhōu # 诌 0x8bcd:cí # 词 0x8bce:qū # 诎 0x8bcf:zhào # 诏 0x8bd0:bì # 诐 0x8bd1:yì # 译 0x8bd2:yí,dài # 诒 0x8bd3:kuāng # 诓 0x8bd4:lěi # 诔 0x8bd5:shì # 试 0x8bd6:guà # 诖 0x8bd7:shī # 诗 0x8bd8:jié,jí # 诘 0x8bd9:huī # 诙 0x8bda:chéng # 诚 0x8bdb:zhū # 诛 0x8bdc:shēn # 诜 0x8bdd:huà # 话 0x8bde:dàn # 诞 0x8bdf:gòu # 诟 0x8be0:quán # 诠 0x8be1:guǐ # 诡 0x8be2:xún # 询 0x8be3:yì # 诣 0x8be4:zhèng # 诤 0x8be5:gāi # 该 0x8be6:xiáng,yáng # 详 0x8be7:chà # 诧 0x8be8:hùn # 诨 0x8be9:xǔ # 诩 0x8bea:zhōu,chóu # 诪 0x8beb:jiè # 诫 0x8bec:wū # 诬 0x8bed:yǔ,yù # 语 0x8bee:qiào # 诮 0x8bef:wù # 误 0x8bf0:gào # 诰 0x8bf1:yòu # 诱 0x8bf2:huì # 诲 0x8bf3:kuáng # 诳 0x8bf4:shuō,shuì,yuè # 说 0x8bf5:sòng # 诵 0x8bf6:ēi,éi,ěi,èi,xī # 诶 0x8bf7:qǐng # 请 0x8bf8:zhū # 诸 0x8bf9:zōu # 诹 0x8bfa:nuò # 诺 0x8bfb:dú,dòu # 读 0x8bfc:zhuó # 诼 0x8bfd:fěi # 诽 0x8bfe:kè # 课 0x8bff:wěi # 诿 0x8c00:yú # 谀 0x8c01:shuí,shéi # 谁 0x8c02:shěn # 谂 0x8c03:tiáo,diào,zhōu # 调 0x8c04:chǎn # 谄 0x8c05:liàng # 谅 0x8c06:zhūn # 谆 0x8c07:suì # 谇 0x8c08:tán # 谈 0x8c09:shěn # 谉 0x8c0a:yì # 谊 0x8c0b:móu # 谋 0x8c0c:chén,shèn # 谌 0x8c0d:dié # 谍 0x8c0e:huǎng # 谎 0x8c0f:jiàn # 谏 0x8c10:xié # 谐 0x8c11:xuè # 谑 0x8c12:yè # 谒 0x8c13:wèi # 谓 0x8c14:è # 谔 0x8c15:yù # 谕 0x8c16:xuān # 谖 0x8c17:chán # 谗 0x8c18:zī # 谘 0x8c19:ān # 谙 0x8c1a:yàn # 谚 0x8c1b:dì # 谛 0x8c1c:mí,mèi # 谜 0x8c1d:piǎn # 谝 0x8c1e:xū # 谞 0x8c1f:mó # 谟 0x8c20:dǎng # 谠 0x8c21:sù # 谡 0x8c22:xiè # 谢 0x8c23:yáo # 谣 0x8c24:bàng # 谤 0x8c25:shì # 谥 0x8c26:qiān # 谦 0x8c27:mì # 谧 0x8c28:jǐn # 谨 0x8c29:mán # 谩 0x8c2a:zhé # 谪 0x8c2b:jiǎn # 谫 0x8c2c:miù # 谬 0x8c2d:tán # 谭 0x8c2e:zèn # 谮 0x8c2f:qiáo # 谯 0x8c30:lán # 谰 0x8c31:pǔ # 谱 0x8c32:jué # 谲 0x8c33:yàn # 谳 0x8c34:qiǎn # 谴 0x8c35:zhān # 谵 0x8c36:chèn # 谶 0x8c37:gǔ,yù # 谷 0x8c38:qiān # 谸 0x8c39:hóng # 谹 0x8c3a:xiā # 谺 0x8c3b:jí # 谻 0x8c3c:hóng # 谼 0x8c3d:hān # 谽 0x8c3e:hōng # 谾 0x8c3f:xī # 谿 0x8c40:xī # 豀 0x8c41:huō,huò,huá # 豁 0x8c42:liáo # 豂 0x8c43:hǎn # 豃 0x8c44:dú # 豄 0x8c45:lóng # 豅 0x8c46:dòu # 豆 0x8c47:jiāng # 豇 0x8c48:qǐ,kǎi # 豈 0x8c49:chǐ # 豉 0x8c4a:lǐ # 豊 0x8c4b:dēng # 豋 0x8c4c:wān # 豌 0x8c4d:bī # 豍 0x8c4e:shù # 豎 0x8c4f:xiàn # 豏 0x8c50:fēng # 豐 0x8c51:zhì # 豑 0x8c52:zhì # 豒 0x8c53:yàn # 豓 0x8c54:yàn # 豔 0x8c55:shǐ # 豕 0x8c56:chù # 豖 0x8c57:huī # 豗 0x8c58:tún # 豘 0x8c59:yì # 豙 0x8c5a:tún # 豚 0x8c5b:yì # 豛 0x8c5c:jiān # 豜 0x8c5d:bā # 豝 0x8c5e:hòu # 豞 0x8c5f:è # 豟 0x8c60:chú # 豠 0x8c61:xiàng # 象 0x8c62:huàn # 豢 0x8c63:jiān,yàn # 豣 0x8c64:kěn # 豤 0x8c65:gāi # 豥 0x8c66:jù # 豦 0x8c67:fú # 豧 0x8c68:xī # 豨 0x8c69:bīn # 豩 0x8c6a:háo # 豪 0x8c6b:yù # 豫 0x8c6c:zhū # 豬 0x8c6d:jiā # 豭 0x8c6e:fén # 豮 0x8c6f:xī # 豯 0x8c70:hù # 豰 0x8c71:wēn # 豱 0x8c72:huán # 豲 0x8c73:bīn # 豳 0x8c74:dí # 豴 0x8c75:zōng # 豵 0x8c76:fén # 豶 0x8c77:yì # 豷 0x8c78:zhì # 豸 0x8c79:bào # 豹 0x8c7a:chái # 豺 0x8c7b:àn # 豻 0x8c7c:pí # 豼 0x8c7d:nà # 豽 0x8c7e:pī # 豾 0x8c7f:gǒu # 豿 0x8c80:nà # 貀 0x8c81:yòu # 貁 0x8c82:diāo # 貂 0x8c83:mò # 貃 0x8c84:sì # 貄 0x8c85:xiū # 貅 0x8c86:huán,huān # 貆 0x8c87:kěn,kūn # 貇 0x8c88:hé,mò # 貈 0x8c89:hé,háo,mò # 貉 0x8c8a:mò # 貊 0x8c8b:àn # 貋 0x8c8c:mào # 貌 0x8c8d:lí # 貍 0x8c8e:ní # 貎 0x8c8f:bǐ # 貏 0x8c90:yǔ # 貐 0x8c91:jiā # 貑 0x8c92:tuān,tuàn # 貒 0x8c93:māo,máo # 貓 0x8c94:pí # 貔 0x8c95:xī # 貕 0x8c96:yì # 貖 0x8c97:jù,lóu # 貗 0x8c98:mò # 貘 0x8c99:chū # 貙 0x8c9a:tán # 貚 0x8c9b:huān # 貛 0x8c9c:jué # 貜 0x8c9d:bèi # 貝 0x8c9e:zhēn # 貞 0x8c9f:yuán,yún,yùn # 貟 0x8ca0:fù # 負 0x8ca1:cái # 財 0x8ca2:gòng # 貢 0x8ca3:dài,tè # 貣 0x8ca4:yì,yí # 貤 0x8ca5:háng # 貥 0x8ca6:wán # 貦 0x8ca7:pín # 貧 0x8ca8:huò # 貨 0x8ca9:fàn # 販 0x8caa:tān # 貪 0x8cab:guàn # 貫 0x8cac:zé,zhài # 責 0x8cad:zhì # 貭 0x8cae:èr # 貮 0x8caf:zhù # 貯 0x8cb0:shì # 貰 0x8cb1:bì # 貱 0x8cb2:zī # 貲 0x8cb3:èr # 貳 0x8cb4:guì # 貴 0x8cb5:piǎn # 貵 0x8cb6:biǎn # 貶 0x8cb7:mǎi # 買 0x8cb8:dài # 貸 0x8cb9:shèng # 貹 0x8cba:kuàng # 貺 0x8cbb:fèi # 費 0x8cbc:tiē # 貼 0x8cbd:yí # 貽 0x8cbe:chí # 貾 0x8cbf:mào # 貿 0x8cc0:hè # 賀 0x8cc1:bì,bēn # 賁 0x8cc2:lù # 賂 0x8cc3:lìn # 賃 0x8cc4:huì # 賄 0x8cc5:gāi # 賅 0x8cc6:pián # 賆 0x8cc7:zī # 資 0x8cc8:jiǎ,gǔ,jià # 賈 0x8cc9:xù # 賉 0x8cca:zéi # 賊 0x8ccb:jiǎo # 賋 0x8ccc:gāi # 賌 0x8ccd:zāng # 賍 0x8cce:jiàn # 賎 0x8ccf:yīng # 賏 0x8cd0:jùn # 賐 0x8cd1:zhèn # 賑 0x8cd2:shē # 賒 0x8cd3:bīn # 賓 0x8cd4:bīn # 賔 0x8cd5:qiú # 賕 0x8cd6:shē # 賖 0x8cd7:chuàn # 賗 0x8cd8:zāng # 賘 0x8cd9:zhōu # 賙 0x8cda:lài # 賚 0x8cdb:zàn # 賛 0x8cdc:cì # 賜 0x8cdd:chēn # 賝 0x8cde:shǎng # 賞 0x8cdf:tiǎn # 賟 0x8ce0:péi # 賠 0x8ce1:gēng # 賡 0x8ce2:xián # 賢 0x8ce3:mài # 賣 0x8ce4:jiàn # 賤 0x8ce5:suì # 賥 0x8ce6:fù # 賦 0x8ce7:dǎn # 賧 0x8ce8:cóng # 賨 0x8ce9:cóng # 賩 0x8cea:zhì # 質 0x8ceb:jī # 賫 0x8cec:zhàng # 賬 0x8ced:dǔ # 賭 0x8cee:jìn # 賮 0x8cef:xiōng,mín # 賯 0x8cf0:chǔn # 賰 0x8cf1:yǔn # 賱 0x8cf2:bǎo # 賲 0x8cf3:zāi # 賳 0x8cf4:lài # 賴 0x8cf5:fèng # 賵 0x8cf6:càng # 賶 0x8cf7:jī # 賷 0x8cf8:shèng # 賸 0x8cf9:ài # 賹 0x8cfa:zhuàn,zuàn # 賺 0x8cfb:fù # 賻 0x8cfc:gòu # 購 0x8cfd:sài # 賽 0x8cfe:zé # 賾 0x8cff:liáo # 賿 0x8d00:yì # 贀 0x8d01:bài # 贁 0x8d02:chěn # 贂 0x8d03:wàn,zhuàn # 贃 0x8d04:zhì # 贄 0x8d05:zhuì # 贅 0x8d06:biāo # 贆 0x8d07:yūn # 贇 0x8d08:zèng # 贈 0x8d09:dàn # 贉 0x8d0a:zàn # 贊 0x8d0b:yàn # 贋 0x8d0d:shàn # 贍 0x8d0e:wàn # 贎 0x8d0f:yíng # 贏 0x8d10:jìn # 贐 0x8d11:gàn # 贑 0x8d12:xián # 贒 0x8d13:zāng # 贓 0x8d14:bì # 贔 0x8d15:dú # 贕 0x8d16:shú # 贖 0x8d17:yàn # 贗 0x8d19:xuàn # 贙 0x8d1a:lòng # 贚 0x8d1b:gàn # 贛 0x8d1c:zāng # 贜 0x8d1d:bèi # 贝 0x8d1e:zhēn # 贞 0x8d1f:fù # 负 0x8d20:yuán,yùn # 贠 0x8d21:gòng # 贡 0x8d22:cái # 财 0x8d23:zé,zhài # 责 0x8d24:xián # 贤 0x8d25:bài # 败 0x8d26:zhàng # 账 0x8d27:huò # 货 0x8d28:zhì # 质 0x8d29:fàn # 贩 0x8d2a:tān # 贪 0x8d2b:pín # 贫 0x8d2c:biǎn # 贬 0x8d2d:gòu # 购 0x8d2e:zhù # 贮 0x8d2f:guàn # 贯 0x8d30:èr # 贰 0x8d31:jiàn # 贱 0x8d32:bì,bēn # 贲 0x8d33:shì # 贳 0x8d34:tiē # 贴 0x8d35:guì # 贵 0x8d36:kuàng # 贶 0x8d37:dài # 贷 0x8d38:mào # 贸 0x8d39:fèi # 费 0x8d3a:hè # 贺 0x8d3b:yí # 贻 0x8d3c:zéi # 贼 0x8d3d:zhì # 贽 0x8d3e:gǔ,jiǎ # 贾 0x8d3f:huì # 贿 0x8d40:zī # 赀 0x8d41:lìn # 赁 0x8d42:lù # 赂 0x8d43:zāng # 赃 0x8d44:zī # 资 0x8d45:gāi # 赅 0x8d46:jìn # 赆 0x8d47:qiú # 赇 0x8d48:zhèn # 赈 0x8d49:lài # 赉 0x8d4a:shē # 赊 0x8d4b:fù # 赋 0x8d4c:dǔ # 赌 0x8d4d:jī # 赍 0x8d4e:shú # 赎 0x8d4f:shǎng # 赏 0x8d50:cì # 赐 0x8d51:bì # 赑 0x8d52:zhōu # 赒 0x8d53:gēng # 赓 0x8d54:péi # 赔 0x8d55:dǎn # 赕 0x8d56:lài # 赖 0x8d57:fèng # 赗 0x8d58:zhuì # 赘 0x8d59:fù # 赙 0x8d5a:zhuàn # 赚 0x8d5b:sài # 赛 0x8d5c:zé # 赜 0x8d5d:yàn # 赝 0x8d5e:zàn # 赞 0x8d5f:yūn # 赟 0x8d60:zèng # 赠 0x8d61:shàn # 赡 0x8d62:yíng # 赢 0x8d63:gàn # 赣 0x8d64:chì # 赤 0x8d65:xī # 赥 0x8d66:shè # 赦 0x8d67:nǎn # 赧 0x8d68:tóng # 赨 0x8d69:xì # 赩 0x8d6a:chēng # 赪 0x8d6b:hè # 赫 0x8d6c:chēng # 赬 0x8d6d:zhě # 赭 0x8d6e:xiá # 赮 0x8d6f:táng # 赯 0x8d70:zǒu # 走 0x8d71:zǒu # 赱 0x8d72:lì # 赲 0x8d73:jiū # 赳 0x8d74:fù # 赴 0x8d75:zhào # 赵 0x8d76:gǎn # 赶 0x8d77:qǐ # 起 0x8d78:shàn # 赸 0x8d79:qióng # 赹 0x8d7a:yǐn # 赺 0x8d7b:xiǎn # 赻 0x8d7c:zī # 赼 0x8d7d:jué # 赽 0x8d7e:qǐn # 赾 0x8d7f:chí # 赿 0x8d80:cī # 趀 0x8d81:chèn # 趁 0x8d82:chèn # 趂 0x8d83:dié,tú # 趃 0x8d84:qiè,jū # 趄 0x8d85:chāo # 超 0x8d86:dī # 趆 0x8d87:xì # 趇 0x8d88:zhān # 趈 0x8d89:jué # 趉 0x8d8a:yuè # 越 0x8d8b:qū,cù # 趋 0x8d8c:jí,jié # 趌 0x8d8d:qū # 趍 0x8d8e:chú # 趎 0x8d8f:guā,huó # 趏 0x8d90:xuè # 趐 0x8d91:zī # 趑 0x8d92:tiào # 趒 0x8d93:duǒ # 趓 0x8d94:liè # 趔 0x8d95:gǎn # 趕 0x8d96:suō # 趖 0x8d97:cù # 趗 0x8d98:xí # 趘 0x8d99:zhào # 趙 0x8d9a:sù # 趚 0x8d9b:yǐn # 趛 0x8d9c:jú # 趜 0x8d9d:jiàn # 趝 0x8d9e:què,qì,jí # 趞 0x8d9f:tàng,tāng # 趟 0x8da0:chuō,zhuó # 趠 0x8da1:cuǐ # 趡 0x8da2:lù # 趢 0x8da3:qù,cù # 趣 0x8da4:dàng # 趤 0x8da5:qiū # 趥 0x8da6:zī # 趦 0x8da7:tí # 趧 0x8da8:qū,cù # 趨 0x8da9:chì # 趩 0x8daa:huáng # 趪 0x8dab:qiáo # 趫 0x8dac:qiāo # 趬 0x8dad:jiào # 趭 0x8dae:zào # 趮 0x8daf:tì,yuè # 趯 0x8db1:zǎn # 趱 0x8db2:zǎn # 趲 0x8db3:zú # 足 0x8db4:pā # 趴 0x8db5:bào,bō # 趵 0x8db6:kuà,wù # 趶 0x8db7:kē # 趷 0x8db8:dǔn # 趸 0x8db9:jué,guì # 趹 0x8dba:fū # 趺 0x8dbb:chěn # 趻 0x8dbc:jiǎn # 趼 0x8dbd:fāng,fàng,páng # 趽 0x8dbe:zhǐ # 趾 0x8dbf:tā # 趿 0x8dc0:yuè # 跀 0x8dc1:bà,páo # 跁 0x8dc2:qí,qǐ # 跂 0x8dc3:yuè # 跃 0x8dc4:qiāng,qiàng # 跄 0x8dc5:tuò # 跅 0x8dc6:tái # 跆 0x8dc7:yì # 跇 0x8dc8:jiàn,chén # 跈 0x8dc9:líng # 跉 0x8dca:mèi # 跊 0x8dcb:bá # 跋 0x8dcc:diē # 跌 0x8dcd:kū # 跍 0x8dce:tuó # 跎 0x8dcf:jiā # 跏 0x8dd0:cī,cǐ # 跐 0x8dd1:pǎo,páo # 跑 0x8dd2:qiǎ # 跒 0x8dd3:zhù # 跓 0x8dd4:jū # 跔 0x8dd5:diǎn,tiē,dié # 跕 0x8dd6:zhí # 跖 0x8dd7:fū # 跗 0x8dd8:pán,bàn # 跘 0x8dd9:jū,jù,qiè # 跙 0x8dda:shān # 跚 0x8ddb:bǒ # 跛 0x8ddc:ní # 跜 0x8ddd:jù # 距 0x8dde:lì,luò # 跞 0x8ddf:gēn # 跟 0x8de0:yí # 跠 0x8de1:jì # 跡 0x8de2:dài,duò,duō,chí # 跢 0x8de3:xiǎn # 跣 0x8de4:jiāo # 跤 0x8de5:duò # 跥 0x8de6:zhū # 跦 0x8de7:quán # 跧 0x8de8:kuà # 跨 0x8de9:zhuǎi # 跩 0x8dea:guì # 跪 0x8deb:qióng # 跫 0x8dec:kuǐ # 跬 0x8ded:xiáng # 跭 0x8dee:dié # 跮 0x8def:lù # 路 0x8df0:pián,bèng # 跰 0x8df1:zhì # 跱 0x8df2:jié # 跲 0x8df3:tiào,táo # 跳 0x8df4:cǎi # 跴 0x8df5:jiàn # 践 0x8df6:dá # 跶 0x8df7:qiāo # 跷 0x8df8:bì # 跸 0x8df9:xiān # 跹 0x8dfa:duò # 跺 0x8dfb:jī # 跻 0x8dfc:jú # 跼 0x8dfd:jì # 跽 0x8dfe:shū,chōu # 跾 0x8dff:tú # 跿 0x8e00:chuò # 踀 0x8e01:jìng # 踁 0x8e02:niè # 踂 0x8e03:xiāo # 踃 0x8e04:bù # 踄 0x8e05:xué # 踅 0x8e06:cūn # 踆 0x8e07:mǔ # 踇 0x8e08:shū # 踈 0x8e09:liáng,liàng # 踉 0x8e0a:yǒng # 踊 0x8e0b:jiǎo # 踋 0x8e0c:chóu # 踌 0x8e0d:qiāo # 踍 0x8e0f:tà # 踏 0x8e10:jiàn # 踐 0x8e11:jī # 踑 0x8e12:wō # 踒 0x8e13:wěi # 踓 0x8e14:chuō # 踔 0x8e15:jié # 踕 0x8e16:jí # 踖 0x8e17:niè # 踗 0x8e18:jū # 踘 0x8e19:niè # 踙 0x8e1a:lún # 踚 0x8e1b:lù # 踛 0x8e1c:lèng # 踜 0x8e1d:huái # 踝 0x8e1e:jù # 踞 0x8e1f:chí # 踟 0x8e20:wǎn # 踠 0x8e21:quán # 踡 0x8e22:tī # 踢 0x8e23:bó # 踣 0x8e24:zú # 踤 0x8e25:qiè # 踥 0x8e26:qī,yǐ # 踦 0x8e27:cù # 踧 0x8e28:zōng # 踨 0x8e29:cǎi # 踩 0x8e2a:zōng # 踪 0x8e2b:pèng # 踫 0x8e2c:zhì # 踬 0x8e2d:zhēng # 踭 0x8e2e:diǎn # 踮 0x8e2f:zhí # 踯 0x8e30:yú # 踰 0x8e31:duó # 踱 0x8e32:dùn # 踲 0x8e33:chuǎn # 踳 0x8e34:yǒng # 踴 0x8e35:zhǒng # 踵 0x8e36:dì # 踶 0x8e37:zhě # 踷 0x8e38:chěn # 踸 0x8e39:chuài # 踹 0x8e3a:jiàn # 踺 0x8e3b:guā # 踻 0x8e3c:táng # 踼 0x8e3d:jǔ # 踽 0x8e3e:fú # 踾 0x8e3f:cù # 踿 0x8e40:dié # 蹀 0x8e41:pián # 蹁 0x8e42:róu # 蹂 0x8e43:nuò # 蹃 0x8e44:tí # 蹄 0x8e45:chǎ # 蹅 0x8e46:tuǐ # 蹆 0x8e47:jiǎn # 蹇 0x8e48:dǎo # 蹈 0x8e49:cuō # 蹉 0x8e4a:qī,xī # 蹊 0x8e4b:tà # 蹋 0x8e4c:qiāng # 蹌 0x8e4d:niǎn # 蹍 0x8e4e:diān # 蹎 0x8e4f:tí # 蹏 0x8e50:jí # 蹐 0x8e51:niè # 蹑 0x8e52:pán # 蹒 0x8e53:liū # 蹓 0x8e54:zàn # 蹔 0x8e55:bì # 蹕 0x8e56:chōng # 蹖 0x8e57:lù # 蹗 0x8e58:liáo # 蹘 0x8e59:cù # 蹙 0x8e5a:tāng # 蹚 0x8e5b:dài # 蹛 0x8e5c:sù # 蹜 0x8e5d:xǐ # 蹝 0x8e5e:kuǐ # 蹞 0x8e5f:jì # 蹟 0x8e60:zhí # 蹠 0x8e61:qiāng # 蹡 0x8e62:dí,zhí # 蹢 0x8e63:pán # 蹣 0x8e64:zōng # 蹤 0x8e65:lián # 蹥 0x8e66:bèng # 蹦 0x8e67:zāo # 蹧 0x8e68:niǎn # 蹨 0x8e69:bié # 蹩 0x8e6a:tuí # 蹪 0x8e6b:jú # 蹫 0x8e6c:dēng # 蹬 0x8e6d:cèng # 蹭 0x8e6e:xiān # 蹮 0x8e6f:fán # 蹯 0x8e70:chú # 蹰 0x8e71:zhōng # 蹱 0x8e72:dūn,cún # 蹲 0x8e73:bō # 蹳 0x8e74:cù,jiu # 蹴 0x8e75:cù # 蹵 0x8e76:jué,juě # 蹶 0x8e77:jué # 蹷 0x8e78:lìn # 蹸 0x8e79:tà # 蹹 0x8e7a:qiāo # 蹺 0x8e7b:qiāo,juē,jiǎo # 蹻 0x8e7c:pǔ # 蹼 0x8e7d:liāo # 蹽 0x8e7e:dūn # 蹾 0x8e7f:cuān # 蹿 0x8e80:guàn # 躀 0x8e81:zào # 躁 0x8e82:tà # 躂 0x8e83:bì # 躃 0x8e84:bì # 躄 0x8e85:zhú # 躅 0x8e86:jù # 躆 0x8e87:chú # 躇 0x8e88:qiào # 躈 0x8e89:dǔn # 躉 0x8e8a:chóu # 躊 0x8e8b:jī # 躋 0x8e8c:wǔ # 躌 0x8e8d:yuè # 躍 0x8e8e:niǎn # 躎 0x8e8f:lìn # 躏 0x8e90:liè # 躐 0x8e91:zhí # 躑 0x8e92:lì,luò # 躒 0x8e93:zhì # 躓 0x8e94:chán # 躔 0x8e95:chú # 躕 0x8e96:duàn # 躖 0x8e97:wèi # 躗 0x8e98:lóng,lǒng # 躘 0x8e99:lìn # 躙 0x8e9a:xiān # 躚 0x8e9b:wèi # 躛 0x8e9c:zuān # 躜 0x8e9d:lán # 躝 0x8e9e:xiè # 躞 0x8e9f:ráng # 躟 0x8ea0:sǎ,xiè # 躠 0x8ea1:niè # 躡 0x8ea2:tà # 躢 0x8ea3:qú # 躣 0x8ea4:jí # 躤 0x8ea5:cuān # 躥 0x8ea6:zuān # 躦 0x8ea7:xǐ # 躧 0x8ea8:kuí # 躨 0x8ea9:jué # 躩 0x8eaa:lìn # 躪 0x8eab:shēn # 身 0x8eac:gōng # 躬 0x8ead:dān # 躭 0x8eaf:qū # 躯 0x8eb0:tǐ # 躰 0x8eb1:duǒ # 躱 0x8eb2:duǒ # 躲 0x8eb3:gōng # 躳 0x8eb4:láng # 躴 0x8eb6:luǒ # 躶 0x8eb7:ǎi # 躷 0x8eb8:jī # 躸 0x8eb9:jū # 躹 0x8eba:tǎng # 躺 0x8ebd:yǎn # 躽 0x8ebf:kāng # 躿 0x8ec0:qū # 軀 0x8ec1:lóu # 軁 0x8ec2:lào # 軂 0x8ec3:duǒ # 軃 0x8ec4:zhí # 軄 0x8ec6:tǐ # 軆 0x8ec7:dào # 軇 0x8ec9:yù # 軉 0x8eca:chē,jū # 車 0x8ecb:yà,zhá,gá # 軋 0x8ecc:guǐ # 軌 0x8ecd:jūn # 軍 0x8ece:wèi # 軎 0x8ecf:yuè # 軏 0x8ed0:xìn,xiàn # 軐 0x8ed1:dài # 軑 0x8ed2:xuān # 軒 0x8ed3:fàn,guǐ # 軓 0x8ed4:rèn # 軔 0x8ed5:shān # 軕 0x8ed6:kuáng # 軖 0x8ed7:shū # 軗 0x8ed8:tún # 軘 0x8ed9:chén # 軙 0x8eda:dài # 軚 0x8edb:è # 軛 0x8edc:nà # 軜 0x8edd:qí # 軝 0x8ede:máo # 軞 0x8edf:ruǎn # 軟 0x8ee0:kuáng # 軠 0x8ee1:qián # 軡 0x8ee2:zhuàn,zhuǎn # 転 0x8ee3:hōng # 軣 0x8ee4:hū # 軤 0x8ee5:qú # 軥 0x8ee6:kuàng # 軦 0x8ee7:dǐ # 軧 0x8ee8:líng # 軨 0x8ee9:dài # 軩 0x8eea:āo,ào # 軪 0x8eeb:zhěn # 軫 0x8eec:fàn # 軬 0x8eed:kuāng # 軭 0x8eee:yǎng # 軮 0x8eef:pēng # 軯 0x8ef0:bèi # 軰 0x8ef1:gū # 軱 0x8ef2:gū # 軲 0x8ef3:páo # 軳 0x8ef4:zhù # 軴 0x8ef5:rǒng # 軵 0x8ef6:è # 軶 0x8ef7:bá # 軷 0x8ef8:zhóu,zhòu # 軸 0x8ef9:zhǐ # 軹 0x8efa:yáo # 軺 0x8efb:kē,kě # 軻 0x8efc:yì,dié # 軼 0x8efd:qīng # 軽 0x8efe:shì # 軾 0x8eff:píng # 軿 0x8f00:ér # 輀 0x8f01:gǒng # 輁 0x8f02:jú # 輂 0x8f03:jiào # 較 0x8f04:guāng # 輄 0x8f05:lù # 輅 0x8f06:kǎi # 輆 0x8f07:quán # 輇 0x8f08:zhōu # 輈 0x8f09:zài # 載 0x8f0a:zhì # 輊 0x8f0b:shē # 輋 0x8f0c:liàng # 輌 0x8f0d:yù # 輍 0x8f0e:shāo # 輎 0x8f0f:yóu # 輏 0x8f10:wàn # 輐 0x8f11:yǐn # 輑 0x8f12:zhé # 輒 0x8f13:wǎn # 輓 0x8f14:fǔ # 輔 0x8f15:qīng # 輕 0x8f16:zhōu # 輖 0x8f17:ní # 輗 0x8f18:líng # 輘 0x8f19:zhé # 輙 0x8f1a:hàn,zhàn # 輚 0x8f1b:liàng # 輛 0x8f1c:zī # 輜 0x8f1d:huī # 輝 0x8f1e:wǎng # 輞 0x8f1f:chuò # 輟 0x8f20:guǒ # 輠 0x8f21:kǎn # 輡 0x8f22:yǐ # 輢 0x8f23:péng # 輣 0x8f24:qiàn # 輤 0x8f25:gǔn # 輥 0x8f26:niǎn # 輦 0x8f27:píng # 輧 0x8f28:guǎn # 輨 0x8f29:bèi # 輩 0x8f2a:lún # 輪 0x8f2b:pái # 輫 0x8f2c:liáng # 輬 0x8f2d:ruǎn # 輭 0x8f2e:róu # 輮 0x8f2f:jí # 輯 0x8f30:yáng # 輰 0x8f31:xián # 輱 0x8f32:chuán # 輲 0x8f33:còu # 輳 0x8f34:chūn # 輴 0x8f35:gé # 輵 0x8f36:yóu # 輶 0x8f37:hōng # 輷 0x8f38:shū # 輸 0x8f39:fù # 輹 0x8f3a:zī # 輺 0x8f3b:fú # 輻 0x8f3c:wēn # 輼 0x8f3d:fàn # 輽 0x8f3e:zhǎn # 輾 0x8f3f:yú # 輿 0x8f40:wēn # 轀 0x8f41:tāo # 轁 0x8f42:gǔ # 轂 0x8f43:zhēn # 轃 0x8f44:xiá # 轄 0x8f45:yuán # 轅 0x8f46:lù # 轆 0x8f47:jiāo # 轇 0x8f48:cháo # 轈 0x8f49:zhuǎn # 轉 0x8f4a:wèi # 轊 0x8f4b:hūn # 轋 0x8f4d:zhé # 轍 0x8f4e:jiào # 轎 0x8f4f:zhàn # 轏 0x8f50:bú # 轐 0x8f51:lǎo # 轑 0x8f52:fén # 轒 0x8f53:fān # 轓 0x8f54:lín # 轔 0x8f55:gé # 轕 0x8f56:sè # 轖 0x8f57:kǎn # 轗 0x8f58:huàn # 轘 0x8f59:yǐ # 轙 0x8f5a:jí # 轚 0x8f5b:duì # 轛 0x8f5c:ér # 轜 0x8f5d:yú # 轝 0x8f5e:jiàn # 轞 0x8f5f:hōng # 轟 0x8f60:léi # 轠 0x8f61:pèi # 轡 0x8f62:lì # 轢 0x8f63:lì # 轣 0x8f64:lú # 轤 0x8f65:lìn # 轥 0x8f66:chē,jū # 车 0x8f67:yà,zhá,gá # 轧 0x8f68:guǐ # 轨 0x8f69:xuān # 轩 0x8f6a:dài # 轪 0x8f6b:rèn # 轫 0x8f6c:zhuǎn,zhuàn,zhuǎi # 转 0x8f6d:è # 轭 0x8f6e:lún # 轮 0x8f6f:ruǎn # 软 0x8f70:hōng # 轰 0x8f71:gū # 轱 0x8f72:kē # 轲 0x8f73:lú # 轳 0x8f74:zhóu,zhòu # 轴 0x8f75:zhǐ # 轵 0x8f76:yì # 轶 0x8f77:hū # 轷 0x8f78:zhěn # 轸 0x8f79:lì # 轹 0x8f7a:yáo # 轺 0x8f7b:qīng # 轻 0x8f7c:shì # 轼 0x8f7d:zǎi,zài # 载 0x8f7e:zhì # 轾 0x8f7f:jiào # 轿 0x8f80:zhōu # 辀 0x8f81:quán # 辁 0x8f82:lù # 辂 0x8f83:jiào # 较 0x8f84:zhé # 辄 0x8f85:fǔ # 辅 0x8f86:liàng # 辆 0x8f87:niǎn # 辇 0x8f88:bèi # 辈 0x8f89:huī # 辉 0x8f8a:gǔn # 辊 0x8f8b:wǎng # 辋 0x8f8c:liáng # 辌 0x8f8d:chuò # 辍 0x8f8e:zī # 辎 0x8f8f:còu # 辏 0x8f90:fú # 辐 0x8f91:jí # 辑 0x8f92:wēn # 辒 0x8f93:shū # 输 0x8f94:pèi # 辔 0x8f95:yuán # 辕 0x8f96:xiá # 辖 0x8f97:zhǎn,niǎn # 辗 0x8f98:lù # 辘 0x8f99:zhé # 辙 0x8f9a:lín # 辚 0x8f9b:xīn # 辛 0x8f9c:gū # 辜 0x8f9d:cí # 辝 0x8f9e:cí # 辞 0x8f9f:bì,pì # 辟 0x8fa0:zuì # 辠 0x8fa1:biàn # 辡 0x8fa2:là # 辢 0x8fa3:là # 辣 0x8fa4:cí # 辤 0x8fa5:xuē # 辥 0x8fa6:bàn # 辦 0x8fa7:biàn # 辧 0x8fa8:biàn # 辨 0x8fa9:biàn # 辩 0x8fab:biàn # 辫 0x8fac:bān # 辬 0x8fad:cí # 辭 0x8fae:biàn # 辮 0x8faf:biàn # 辯 0x8fb0:chén # 辰 0x8fb1:rǔ # 辱 0x8fb2:nóng # 農 0x8fb3:nóng # 辳 0x8fb4:zhěn # 辴 0x8fb5:chuò # 辵 0x8fb6:chuò # 辶 0x8fb8:réng # 辸 0x8fb9:biān # 边 0x8fba:dào,biān # 辺 0x8fbd:liáo # 辽 0x8fbe:dá # 达 0x8fbf:chān # 辿 0x8fc0:gān # 迀 0x8fc1:qiān # 迁 0x8fc2:yū # 迂 0x8fc3:yū # 迃 0x8fc4:qì # 迄 0x8fc5:xùn # 迅 0x8fc6:yǐ,yí # 迆 0x8fc7:guò,guo,guō # 过 0x8fc8:mài # 迈 0x8fc9:qī # 迉 0x8fca:zā # 迊 0x8fcb:wàng,kuāng # 迋 0x8fcd:zhūn # 迍 0x8fce:yíng # 迎 0x8fcf:dá # 迏 0x8fd0:yùn # 运 0x8fd1:jìn # 近 0x8fd2:háng # 迒 0x8fd3:yà # 迓 0x8fd4:fǎn # 返 0x8fd5:wǔ # 迕 0x8fd6:dá # 迖 0x8fd7:é # 迗 0x8fd8:hái,huán # 还 0x8fd9:zhè,zhèi # 这 0x8fdb:jìn # 进 0x8fdc:yuǎn,yuàn # 远 0x8fdd:wéi # 违 0x8fde:lián # 连 0x8fdf:chí # 迟 0x8fe0:chè # 迠 0x8fe1:chí # 迡 0x8fe2:tiáo # 迢 0x8fe3:zhì,lì # 迣 0x8fe4:yǐ,yí # 迤 0x8fe5:jiǒng # 迥 0x8fe6:jiā # 迦 0x8fe7:chén # 迧 0x8fe8:dài # 迨 0x8fe9:ěr # 迩 0x8fea:dí # 迪 0x8feb:pò,pǎi # 迫 0x8fec:zhù,wǎng # 迬 0x8fed:dié # 迭 0x8fee:zé # 迮 0x8fef:táo # 迯 0x8ff0:shù # 述 0x8ff1:yǐ,yí # 迱 0x8ff3:jìng # 迳 0x8ff4:huí # 迴 0x8ff5:dòng # 迵 0x8ff6:yòu # 迶 0x8ff7:mí # 迷 0x8ff8:bèng # 迸 0x8ff9:jì # 迹 0x8ffa:nǎi # 迺 0x8ffb:yí # 迻 0x8ffc:jié # 迼 0x8ffd:zhuī,duī # 追 0x8ffe:liè # 迾 0x8fff:xùn # 迿 0x9000:tuì # 退 0x9001:sòng # 送 0x9002:shì # 适 0x9003:táo # 逃 0x9004:páng # 逄 0x9005:hòu # 逅 0x9006:nì # 逆 0x9007:dùn # 逇 0x9008:jiǒng # 逈 0x9009:xuǎn # 选 0x900a:xùn # 逊 0x900b:bū # 逋 0x900c:yōu # 逌 0x900d:xiāo # 逍 0x900e:qiú # 逎 0x900f:tòu # 透 0x9010:zhú # 逐 0x9011:qiú # 逑 0x9012:dì # 递 0x9013:dì # 逓 0x9014:tú # 途 0x9015:jìng # 逕 0x9016:tì # 逖 0x9017:dòu # 逗 0x9018:yǐ # 逘 0x9019:zhè # 這 0x901a:tōng # 通 0x901b:guàng # 逛 0x901c:wǔ # 逜 0x901d:shì # 逝 0x901e:chěng # 逞 0x901f:sù # 速 0x9020:zào # 造 0x9021:qūn # 逡 0x9022:féng # 逢 0x9023:lián # 連 0x9024:suò # 逤 0x9025:huí # 逥 0x9026:lǐ # 逦 0x9028:lái # 逨 0x9029:bèn # 逩 0x902a:cuò # 逪 0x902b:zhú,jué # 逫 0x902c:bèng # 逬 0x902d:huàn # 逭 0x902e:dài # 逮 0x902f:lù # 逯 0x9030:yóu # 逰 0x9031:zhōu # 週 0x9032:jìn # 進 0x9033:yù # 逳 0x9034:chuō # 逴 0x9035:kuí # 逵 0x9036:wēi # 逶 0x9037:tì # 逷 0x9038:yì # 逸 0x9039:dá # 逹 0x903a:yuǎn # 逺 0x903b:luó # 逻 0x903c:bī # 逼 0x903d:nuò # 逽 0x903e:yú # 逾 0x903f:dàng # 逿 0x9040:suí # 遀 0x9041:dùn # 遁 0x9042:suì # 遂 0x9043:yǎn # 遃 0x9044:chuán # 遄 0x9045:chí # 遅 0x9046:dì,tí # 遆 0x9047:yù # 遇 0x9048:shí # 遈 0x9049:zhēn # 遉 0x904a:yóu # 遊 0x904b:yùn # 運 0x904c:è # 遌 0x904d:biàn # 遍 0x904e:guò # 過 0x904f:è # 遏 0x9050:xiá # 遐 0x9051:huáng # 遑 0x9052:qiú # 遒 0x9053:dào # 道 0x9054:dá # 達 0x9055:wéi # 違 0x9057:yí,wèi # 遗 0x9058:gòu # 遘 0x9059:yáo # 遙 0x905a:chòu # 遚 0x905b:liù # 遛 0x905c:xùn # 遜 0x905d:tà # 遝 0x905e:dì # 遞 0x905f:chí # 遟 0x9060:yuǎn # 遠 0x9061:sù # 遡 0x9062:tà # 遢 0x9063:qiǎn # 遣 0x9065:yáo # 遥 0x9066:guàn # 遦 0x9067:zhāng # 遧 0x9068:áo # 遨 0x9069:shì # 適 0x906a:cà # 遪 0x906b:chì # 遫 0x906c:sù # 遬 0x906d:zāo # 遭 0x906e:zhē # 遮 0x906f:dùn # 遯 0x9070:dì # 遰 0x9071:lóu # 遱 0x9072:chí # 遲 0x9073:cuō # 遳 0x9074:lín # 遴 0x9075:zūn # 遵 0x9076:rào # 遶 0x9077:qiān # 遷 0x9078:xuǎn # 選 0x9079:yù # 遹 0x907a:yí,wèi,suí # 遺 0x907b:è # 遻 0x907c:liáo # 遼 0x907d:jù # 遽 0x907e:shì # 遾 0x907f:bì # 避 0x9080:yāo # 邀 0x9081:mài # 邁 0x9082:xiè # 邂 0x9083:suì # 邃 0x9084:huán,hái # 還 0x9085:zhān # 邅 0x9086:téng # 邆 0x9087:ěr # 邇 0x9088:miǎo # 邈 0x9089:biān # 邉 0x908a:biān # 邊 0x908b:lā # 邋 0x908c:lí,chí # 邌 0x908d:yuán # 邍 0x908e:yáo # 邎 0x908f:luó # 邏 0x9090:lǐ # 邐 0x9091:yì # 邑 0x9092:tíng # 邒 0x9093:dèng # 邓 0x9094:qǐ # 邔 0x9095:yōng # 邕 0x9096:shān # 邖 0x9097:hán # 邗 0x9098:yú # 邘 0x9099:máng # 邙 0x909a:rú # 邚 0x909b:qióng # 邛 0x909d:kuàng # 邝 0x909e:fū # 邞 0x909f:kàng,háng # 邟 0x90a0:bīn # 邠 0x90a1:fāng # 邡 0x90a2:xíng # 邢 0x90a3:nà,nǎ,nèi,nā,nè,nuó # 那 0x90a5:shěn # 邥 0x90a6:bāng # 邦 0x90a7:yuán # 邧 0x90a8:cūn # 邨 0x90a9:huǒ # 邩 0x90aa:xié,yá,yé,yú,xú # 邪 0x90ab:bāng # 邫 0x90ac:wū # 邬 0x90ad:jù # 邭 0x90ae:yóu # 邮 0x90af:hán # 邯 0x90b0:tái # 邰 0x90b1:qiū # 邱 0x90b2:bì # 邲 0x90b3:pī # 邳 0x90b4:bǐng # 邴 0x90b5:shào # 邵 0x90b6:bèi # 邶 0x90b7:wǎ # 邷 0x90b8:dǐ # 邸 0x90b9:zōu # 邹 0x90ba:yè # 邺 0x90bb:lín # 邻 0x90bc:kuāng # 邼 0x90bd:guī # 邽 0x90be:zhū # 邾 0x90bf:shī # 邿 0x90c0:kū # 郀 0x90c1:yù # 郁 0x90c2:gāi,hái # 郂 0x90c3:hé # 郃 0x90c4:qiè,xì # 郄 0x90c5:zhì # 郅 0x90c6:jí # 郆 0x90c7:xún,huán # 郇 0x90c8:hòu # 郈 0x90c9:xíng # 郉 0x90ca:jiāo # 郊 0x90cb:xí # 郋 0x90cc:guī # 郌 0x90cd:nà # 郍 0x90ce:láng,làng # 郎 0x90cf:jiá # 郏 0x90d0:kuài # 郐 0x90d1:zhèng # 郑 0x90d3:yùn # 郓 0x90d4:yán # 郔 0x90d5:chéng # 郕 0x90d6:dòu # 郖 0x90d7:xī # 郗 0x90d8:lǚ # 郘 0x90d9:fǔ # 郙 0x90da:wú # 郚 0x90db:fú # 郛 0x90dc:gào # 郜 0x90dd:hǎo # 郝 0x90de:láng # 郞 0x90df:jiá # 郟 0x90e0:gěng # 郠 0x90e1:jùn # 郡 0x90e2:yǐng # 郢 0x90e3:bó # 郣 0x90e4:xì # 郤 0x90e5:bèi # 郥 0x90e6:lì,zhí # 郦 0x90e7:yún # 郧 0x90e8:bù # 部 0x90e9:xiáo,ǎo # 郩 0x90ea:qī # 郪 0x90eb:pí # 郫 0x90ec:qīng # 郬 0x90ed:guō # 郭 0x90ef:tán # 郯 0x90f0:zōu # 郰 0x90f1:píng # 郱 0x90f2:lái # 郲 0x90f3:ní # 郳 0x90f4:chēn # 郴 0x90f5:yóu # 郵 0x90f6:bù # 郶 0x90f7:xiāng # 郷 0x90f8:dān # 郸 0x90f9:jú # 郹 0x90fa:yōng # 郺 0x90fb:qiāo # 郻 0x90fc:yī # 郼 0x90fd:dōu,dū # 都 0x90fe:yǎn # 郾 0x90ff:méi # 郿 0x9100:ruò # 鄀 0x9101:bèi # 鄁 0x9102:è # 鄂 0x9103:shū # 鄃 0x9104:juàn # 鄄 0x9105:yǔ # 鄅 0x9106:yùn # 鄆 0x9107:hóu # 鄇 0x9108:kuí # 鄈 0x9109:xiāng # 鄉 0x910a:xiāng # 鄊 0x910b:sōu # 鄋 0x910c:táng # 鄌 0x910d:míng # 鄍 0x910e:xī # 鄎 0x910f:rǔ # 鄏 0x9110:chù # 鄐 0x9111:zī # 鄑 0x9112:zōu # 鄒 0x9113:yì # 鄓 0x9114:wū # 鄔 0x9115:xiāng # 鄕 0x9116:yún # 鄖 0x9117:hào # 鄗 0x9118:yōng # 鄘 0x9119:bǐ # 鄙 0x911a:mào # 鄚 0x911b:cháo # 鄛 0x911c:fū # 鄜 0x911d:liǎo # 鄝 0x911e:yín # 鄞 0x911f:zhuān # 鄟 0x9120:hù # 鄠 0x9121:qiāo # 鄡 0x9122:yān # 鄢 0x9123:zhāng # 鄣 0x9124:màn # 鄤 0x9125:qiāo # 鄥 0x9126:xǔ # 鄦 0x9127:dèng # 鄧 0x9128:bì # 鄨 0x9129:xún # 鄩 0x912a:bì # 鄪 0x912b:zēng # 鄫 0x912c:wéi # 鄬 0x912d:zhèng # 鄭 0x912e:mào # 鄮 0x912f:shàn # 鄯 0x9130:lín # 鄰 0x9131:pó # 鄱 0x9132:dān # 鄲 0x9133:méng # 鄳 0x9134:yè # 鄴 0x9135:cào # 鄵 0x9136:kuài # 鄶 0x9137:fēng # 鄷 0x9138:méng # 鄸 0x9139:zōu # 鄹 0x913a:kuàng # 鄺 0x913b:liǎn # 鄻 0x913c:zàn # 鄼 0x913d:chán # 鄽 0x913e:yōu # 鄾 0x913f:qí # 鄿 0x9140:yàn # 酀 0x9141:chán # 酁 0x9142:cuó,zàn # 酂 0x9143:líng # 酃 0x9144:huān # 酄 0x9145:xī # 酅 0x9146:fēng # 酆 0x9147:cuó,zàn # 酇 0x9148:lì # 酈 0x9149:yǒu # 酉 0x914a:dīng,dǐng # 酊 0x914b:qiú # 酋 0x914c:zhuó # 酌 0x914d:pèi # 配 0x914e:zhòu # 酎 0x914f:yǐ # 酏 0x9150:gān # 酐 0x9151:yú # 酑 0x9152:jiǔ # 酒 0x9153:yǎn # 酓 0x9154:zuì # 酔 0x9155:máo # 酕 0x9156:dān # 酖 0x9157:xù # 酗 0x9158:dòu # 酘 0x9159:zhēn # 酙 0x915a:fēn # 酚 0x915d:yùn # 酝 0x915e:tài # 酞 0x915f:tiān # 酟 0x9160:qiǎ # 酠 0x9161:tuó # 酡 0x9162:zuò,cù # 酢 0x9163:hān # 酣 0x9164:gū # 酤 0x9165:sū # 酥 0x9166:pō,fā # 酦 0x9167:chóu # 酧 0x9168:zài # 酨 0x9169:mǐng # 酩 0x916a:lào # 酪 0x916b:chuò # 酫 0x916c:chóu # 酬 0x916d:yòu # 酭 0x916e:tóng # 酮 0x916f:zhǐ # 酯 0x9170:xiān # 酰 0x9171:jiàng # 酱 0x9172:chéng # 酲 0x9173:yìn # 酳 0x9174:tú # 酴 0x9175:jiào # 酵 0x9176:méi # 酶 0x9177:kù # 酷 0x9178:suān # 酸 0x9179:lèi # 酹 0x917a:pú # 酺 0x917b:zuì # 酻 0x917c:hǎi # 酼 0x917d:yàn # 酽 0x917e:shī,shāi # 酾 0x917f:niàng # 酿 0x9180:wéi # 醀 0x9181:lù # 醁 0x9182:lǎn # 醂 0x9183:yān # 醃 0x9184:táo # 醄 0x9185:pēi # 醅 0x9186:zhǎn # 醆 0x9187:chún # 醇 0x9188:tán,dàn # 醈 0x9189:zuì # 醉 0x918a:zhuì # 醊 0x918b:cù # 醋 0x918c:kūn # 醌 0x918d:tí,tǐ # 醍 0x918e:xián # 醎 0x918f:dū # 醏 0x9190:hú # 醐 0x9191:xǔ # 醑 0x9192:xǐng # 醒 0x9193:tǎn # 醓 0x9194:qiú,chōu # 醔 0x9195:chún # 醕 0x9196:yùn # 醖 0x9197:pō,fā # 醗 0x9198:kē # 醘 0x9199:sōu # 醙 0x919a:mí # 醚 0x919b:quán # 醛 0x919c:chǒu # 醜 0x919d:cuō # 醝 0x919e:yùn # 醞 0x919f:yòng # 醟 0x91a0:àng # 醠 0x91a1:zhà # 醡 0x91a2:hǎi # 醢 0x91a3:táng # 醣 0x91a4:jiàng # 醤 0x91a5:piǎo # 醥 0x91a6:chǎn,chěn # 醦 0x91a7:yù # 醧 0x91a8:lí # 醨 0x91a9:zāo # 醩 0x91aa:láo # 醪 0x91ab:yī # 醫 0x91ac:jiàng # 醬 0x91ad:bú # 醭 0x91ae:jiào # 醮 0x91af:xī # 醯 0x91b0:tán # 醰 0x91b1:pō,fā # 醱 0x91b2:nóng # 醲 0x91b3:yì,shì # 醳 0x91b4:lǐ # 醴 0x91b5:jù # 醵 0x91b6:yàn,liǎn,xiān # 醶 0x91b7:yì # 醷 0x91b8:niàng # 醸 0x91b9:rú # 醹 0x91ba:xūn # 醺 0x91bb:chóu # 醻 0x91bc:yàn # 醼 0x91bd:líng # 醽 0x91be:mí # 醾 0x91bf:mí # 醿 0x91c0:niàng,niáng # 釀 0x91c1:xìn # 釁 0x91c2:jiào # 釂 0x91c3:shī # 釃 0x91c4:mí # 釄 0x91c5:yàn # 釅 0x91c6:biàn # 釆 0x91c7:cǎi,cài # 采 0x91c8:shì # 釈 0x91c9:yòu # 釉 0x91ca:shì # 释 0x91cb:shì # 釋 0x91cc:lǐ # 里 0x91cd:zhòng,chóng # 重 0x91ce:yě # 野 0x91cf:liáng,liàng # 量 0x91d0:lí,xǐ,xī # 釐 0x91d1:jīn # 金 0x91d3:gá # 釓 0x91d4:yǐ # 釔 0x91d5:liǎo,liào # 釕 0x91d6:dāo # 釖 0x91d7:zhāo # 釗 0x91d8:dīng,dìng # 釘 0x91d9:pō # 釙 0x91da:qiú # 釚 0x91db:hé # 釛 0x91dc:fǔ # 釜 0x91dd:zhēn # 針 0x91de:zhí # 釞 0x91df:bā # 釟 0x91e0:luàn # 釠 0x91e1:fǔ # 釡 0x91e2:nǎi # 釢 0x91e3:diào # 釣 0x91e4:shān,shàn # 釤 0x91e5:qiǎo,jiǎo # 釥 0x91e6:kòu # 釦 0x91e7:chuàn # 釧 0x91e8:zǐ # 釨 0x91e9:fán # 釩 0x91ea:huá,yú # 釪 0x91eb:huá,wū # 釫 0x91ec:hàn # 釬 0x91ed:gāng # 釭 0x91ee:qí # 釮 0x91ef:máng # 釯 0x91f0:rì,rèn,jiàn # 釰 0x91f1:dì,dài # 釱 0x91f2:sì # 釲 0x91f3:xì # 釳 0x91f4:yì # 釴 0x91f5:chāi # 釵 0x91f6:shī,yí # 釶 0x91f7:tǔ # 釷 0x91f8:xī # 釸 0x91f9:nǚ # 釹 0x91fa:qiān # 釺 0x91fc:rì,rèn,jiàn # 釼 0x91fd:pī,zhāo # 釽 0x91fe:yé,yá # 釾 0x91ff:jīn,yǐn,yín # 釿 0x9200:bǎ,pá # 鈀 0x9201:fāng # 鈁 0x9202:chén # 鈂 0x9203:xíng # 鈃 0x9204:dǒu # 鈄 0x9205:yuè # 鈅 0x9206:qiān # 鈆 0x9207:fū # 鈇 0x9208:bù # 鈈 0x9209:nà # 鈉 0x920a:xīn # 鈊 0x920b:é # 鈋 0x920c:jué # 鈌 0x920d:dùn # 鈍 0x920e:gōu # 鈎 0x920f:yǐn # 鈏 0x9210:qián # 鈐 0x9211:bǎn # 鈑 0x9212:sà # 鈒 0x9213:rèn # 鈓 0x9214:chāo # 鈔 0x9215:niǔ # 鈕 0x9216:fēn # 鈖 0x9217:yǔn # 鈗 0x9218:yǐ # 鈘 0x9219:qín # 鈙 0x921a:pī # 鈚 0x921b:guō # 鈛 0x921c:hóng # 鈜 0x921d:yín # 鈝 0x921e:jūn # 鈞 0x921f:diào # 鈟 0x9220:yì # 鈠 0x9221:zhōng # 鈡 0x9222:xǐ # 鈢 0x9223:gài # 鈣 0x9224:rì # 鈤 0x9225:huǒ # 鈥 0x9226:tài # 鈦 0x9227:kàng # 鈧 0x922c:duó # 鈬 0x922d:zī # 鈭 0x922e:ní # 鈮 0x922f:tú # 鈯 0x9230:shì # 鈰 0x9231:mín # 鈱 0x9232:gū # 鈲 0x9233:kē # 鈳 0x9234:líng # 鈴 0x9235:bǐng # 鈵 0x9236:sì # 鈶 0x9237:gǔ # 鈷 0x9238:bó # 鈸 0x9239:pí # 鈹 0x923a:yù # 鈺 0x923b:sì # 鈻 0x923c:zuó # 鈼 0x923d:bū # 鈽 0x923e:yóu # 鈾 0x923f:diàn # 鈿 0x9240:jiǎ # 鉀 0x9241:zhēn # 鉁 0x9242:shǐ # 鉂 0x9243:shì # 鉃 0x9244:tiě # 鉄 0x9245:jù # 鉅 0x9246:zuān # 鉆 0x9247:shī # 鉇 0x9248:tā,tuó # 鉈 0x9249:xuàn # 鉉 0x924a:zhāo # 鉊 0x924b:bào,páo # 鉋 0x924c:hé # 鉌 0x924d:bì # 鉍 0x924e:shēng # 鉎 0x924f:chú # 鉏 0x9250:shí # 鉐 0x9251:bó # 鉑 0x9252:zhù # 鉒 0x9253:chì # 鉓 0x9254:zā # 鉔 0x9255:pǒ # 鉕 0x9256:tóng # 鉖 0x9257:qián # 鉗 0x9258:fú # 鉘 0x9259:zhǎi # 鉙 0x925a:mǎo # 鉚 0x925b:qiān # 鉛 0x925c:fú # 鉜 0x925d:lì # 鉝 0x925e:yuè # 鉞 0x925f:pī # 鉟 0x9260:yāng # 鉠 0x9261:bàn # 鉡 0x9262:bō # 鉢 0x9263:jié # 鉣 0x9264:gōu # 鉤 0x9265:shù # 鉥 0x9266:zhēng # 鉦 0x9267:mǔ # 鉧 0x9268:xǐ # 鉨 0x9269:xǐ # 鉩 0x926a:dì # 鉪 0x926b:jiā # 鉫 0x926c:mù # 鉬 0x926d:tǎn # 鉭 0x926e:shén # 鉮 0x926f:yǐ # 鉯 0x9270:sī # 鉰 0x9271:kuàng # 鉱 0x9272:kǎ # 鉲 0x9273:běi # 鉳 0x9274:jiàn # 鉴 0x9275:tóng # 鉵 0x9276:xíng # 鉶 0x9277:hóng # 鉷 0x9278:jiǎo # 鉸 0x9279:chǐ # 鉹 0x927a:ěr # 鉺 0x927b:gè # 鉻 0x927c:bǐng,píng # 鉼 0x927d:shì # 鉽 0x927e:máo # 鉾 0x927f:hā,kē # 鉿 0x9280:yín # 銀 0x9281:jūn # 銁 0x9282:zhōu # 銂 0x9283:chòng # 銃 0x9284:xiǎng,jiōng # 銄 0x9285:tóng # 銅 0x9286:mò # 銆 0x9287:lèi # 銇 0x9288:jī # 銈 0x9289:yù,sì # 銉 0x928a:xù,huì # 銊 0x928b:rén,rěn # 銋 0x928c:zùn # 銌 0x928d:zhì # 銍 0x928e:qióng # 銎 0x928f:shàn,shuò # 銏 0x9290:chì,lì # 銐 0x9291:xiǎn,xǐ # 銑 0x9292:xíng # 銒 0x9293:quán # 銓 0x9294:pī # 銔 0x9295:tiě # 銕 0x9296:zhū # 銖 0x9297:hóu,xiàng # 銗 0x9298:míng # 銘 0x9299:kuǎ # 銙 0x929a:diào,tiáo,yáo # 銚 0x929b:xiān,kuò,tiǎn,guā # 銛 0x929c:xián # 銜 0x929d:xiū # 銝 0x929e:jūn # 銞 0x929f:chā # 銟 0x92a0:lǎo # 銠 0x92a1:jí # 銡 0x92a2:pǐ # 銢 0x92a3:rú # 銣 0x92a4:mǐ # 銤 0x92a5:yī # 銥 0x92a6:yīn # 銦 0x92a7:guāng # 銧 0x92a8:ǎn # 銨 0x92a9:diū # 銩 0x92aa:yǒu # 銪 0x92ab:sè # 銫 0x92ac:kào # 銬 0x92ad:qián # 銭 0x92ae:luán # 銮 0x92b0:āi # 銰 0x92b1:diào # 銱 0x92b2:hàn # 銲 0x92b3:ruì # 銳 0x92b4:shì,zhì # 銴 0x92b5:kēng # 銵 0x92b6:qiú # 銶 0x92b7:xiāo # 銷 0x92b8:zhé,niè # 銸 0x92b9:xiù # 銹 0x92ba:zàng # 銺 0x92bb:tī # 銻 0x92bc:cuò # 銼 0x92bd:xiān,kuò,tiǎn,guā # 銽 0x92be:hòng,gǒng # 銾 0x92bf:zhōng,yōng # 銿 0x92c0:tōu,tù,dòu # 鋀 0x92c1:lǚ # 鋁 0x92c2:méi,méng # 鋂 0x92c3:láng # 鋃 0x92c4:wàn,jiǎn # 鋄 0x92c5:xīn # 鋅 0x92c6:yún # 鋆 0x92c7:bèi # 鋇 0x92c8:wù # 鋈 0x92c9:sù # 鋉 0x92ca:yù # 鋊 0x92cb:chán # 鋋 0x92cc:tǐng,dìng # 鋌 0x92cd:bó # 鋍 0x92ce:hàn # 鋎 0x92cf:jiá # 鋏 0x92d0:hóng # 鋐 0x92d1:juān,jiān,cuān # 鋑 0x92d2:fēng # 鋒 0x92d3:chān # 鋓 0x92d4:wǎn # 鋔 0x92d5:zhì # 鋕 0x92d6:sī,tuó # 鋖 0x92d7:xuān,juān,juàn # 鋗 0x92d8:huá,wú,wū # 鋘 0x92d9:wú,yǔ # 鋙 0x92da:tiáo # 鋚 0x92db:kuàng # 鋛 0x92dc:zhuó,chuò # 鋜 0x92dd:lüè # 鋝 0x92de:xíng,xìng,jīng # 鋞 0x92df:qǐn # 鋟 0x92e0:shèn # 鋠 0x92e1:hán # 鋡 0x92e2:lüè # 鋢 0x92e3:yé # 鋣 0x92e4:chú # 鋤 0x92e5:zèng # 鋥 0x92e6:jū,jú # 鋦 0x92e7:xiàn # 鋧 0x92e8:é # 鋨 0x92e9:máng # 鋩 0x92ea:pū,pù # 鋪 0x92eb:lí # 鋫 0x92ec:pàn # 鋬 0x92ed:ruì # 鋭 0x92ee:chéng # 鋮 0x92ef:gào # 鋯 0x92f0:lǐ # 鋰 0x92f1:tè # 鋱 0x92f3:zhù # 鋳 0x92f5:tū # 鋵 0x92f6:liǔ # 鋶 0x92f7:zuì,niè # 鋷 0x92f8:jù,jū # 鋸 0x92f9:chǎng # 鋹 0x92fa:yuǎn,yuān,wǎn,wān # 鋺 0x92fb:jiān,jiàn # 鋻 0x92fc:gāng,gàng # 鋼 0x92fd:diào # 鋽 0x92fe:táo # 鋾 0x92ff:shǎng # 鋿 0x9300:lún # 錀 0x9301:kè # 錁 0x9302:líng # 錂 0x9303:pī # 錃 0x9304:lù # 錄 0x9305:lí # 錅 0x9306:qīng # 錆 0x9307:péi # 錇 0x9308:juǎn # 錈 0x9309:mín # 錉 0x930a:zuì # 錊 0x930b:péng # 錋 0x930c:àn # 錌 0x930d:pī # 錍 0x930e:xiàn # 錎 0x930f:yā # 錏 0x9310:zhuī # 錐 0x9311:lèi # 錑 0x9312:ā # 錒 0x9313:kōng # 錓 0x9314:tà # 錔 0x9315:kūn # 錕 0x9316:dú # 錖 0x9317:nèi # 錗 0x9318:chuí # 錘 0x9319:zī # 錙 0x931a:zhēng # 錚 0x931b:bēn # 錛 0x931c:niè # 錜 0x931d:cóng # 錝 0x931e:chún,duì # 錞 0x931f:tán # 錟 0x9320:dìng # 錠 0x9321:qí # 錡 0x9322:qián # 錢 0x9323:zhuì # 錣 0x9324:jī # 錤 0x9325:yù # 錥 0x9326:jǐn # 錦 0x9327:guǎn # 錧 0x9328:máo # 錨 0x9329:chāng # 錩 0x932a:tiǎn # 錪 0x932b:xī # 錫 0x932c:liàn # 錬 0x932d:diāo # 錭 0x932e:gù # 錮 0x932f:cuò # 錯 0x9330:shù # 錰 0x9331:zhēn # 錱 0x9332:lù # 録 0x9333:měng # 錳 0x9334:lù # 錴 0x9335:huā # 錵 0x9336:biǎo # 錶 0x9337:gá # 錷 0x9338:lái # 錸 0x9339:kěn # 錹 0x933c:nài # 錼 0x933d:wàn # 錽 0x933e:zàn # 錾 0x9340:dé # 鍀 0x9341:xiān # 鍁 0x9343:huò # 鍃 0x9344:liàng # 鍄 0x9346:mén # 鍆 0x9347:kǎi # 鍇 0x9348:yāng # 鍈 0x9349:chí # 鍉 0x934a:liàn # 鍊 0x934b:guō # 鍋 0x934c:xiǎn # 鍌 0x934d:dù # 鍍 0x934e:tú # 鍎 0x934f:wéi # 鍏 0x9350:zōng # 鍐 0x9351:fù # 鍑 0x9352:róu # 鍒 0x9353:jí # 鍓 0x9354:è # 鍔 0x9355:jūn # 鍕 0x9356:chěn # 鍖 0x9357:tí # 鍗 0x9358:zhá # 鍘 0x9359:hù # 鍙 0x935a:yáng # 鍚 0x935b:duàn # 鍛 0x935c:xiá # 鍜 0x935d:yú # 鍝 0x935e:kēng # 鍞 0x935f:shēng # 鍟 0x9360:huáng # 鍠 0x9361:wěi # 鍡 0x9362:fù # 鍢 0x9363:zhāo # 鍣 0x9364:chā # 鍤 0x9365:qiè # 鍥 0x9366:shī # 鍦 0x9367:hōng # 鍧 0x9368:kuí # 鍨 0x9369:nuò # 鍩 0x936a:móu # 鍪 0x936b:qiāo # 鍫 0x936c:qiāo # 鍬 0x936d:hóu # 鍭 0x936e:tōu # 鍮 0x936f:cōng # 鍯 0x9370:huán # 鍰 0x9371:yè # 鍱 0x9372:mín # 鍲 0x9373:jiàn # 鍳 0x9374:duān # 鍴 0x9375:jiàn # 鍵 0x9376:sī # 鍶 0x9377:kuí # 鍷 0x9378:hú # 鍸 0x9379:xuān # 鍹 0x937a:zhě # 鍺 0x937b:jié # 鍻 0x937c:zhēn # 鍼 0x937d:biān # 鍽 0x937e:zhōng # 鍾 0x937f:zī # 鍿 0x9380:xiū # 鎀 0x9381:yé # 鎁 0x9382:měi # 鎂 0x9383:pài # 鎃 0x9384:āi # 鎄 0x9385:jiè # 鎅 0x9387:méi # 鎇 0x9388:cuō,chā # 鎈 0x9389:dā,tà # 鎉 0x938a:bàng # 鎊 0x938b:xiá # 鎋 0x938c:lián # 鎌 0x938d:suǒ,sè # 鎍 0x938e:kài # 鎎 0x938f:liú # 鎏 0x9390:yáo,zú # 鎐 0x9391:yè,tà,gé # 鎑 0x9392:nòu # 鎒 0x9393:wēng # 鎓 0x9394:róng # 鎔 0x9395:táng # 鎕 0x9396:suǒ # 鎖 0x9397:qiāng,chēng # 鎗 0x9398:gé,lì # 鎘 0x9399:shuò # 鎙 0x939a:chuí # 鎚 0x939b:bó # 鎛 0x939c:pán # 鎜 0x939d:dā # 鎝 0x939e:bī,bì,pī # 鎞 0x939f:sǎng # 鎟 0x93a0:gāng # 鎠 0x93a1:zī # 鎡 0x93a2:wū # 鎢 0x93a3:yíng # 鎣 0x93a4:huàng # 鎤 0x93a5:tiáo # 鎥 0x93a6:liú,liù # 鎦 0x93a7:kǎi # 鎧 0x93a8:sǔn # 鎨 0x93a9:shā # 鎩 0x93aa:sōu # 鎪 0x93ab:wàn,jiǎn # 鎫 0x93ac:gǎo,hào # 鎬 0x93ad:zhèn # 鎭 0x93ae:zhèn # 鎮 0x93af:láng # 鎯 0x93b0:yì # 鎰 0x93b1:yuán # 鎱 0x93b2:tǎng # 鎲 0x93b3:niè # 鎳 0x93b4:xí # 鎴 0x93b5:jiā # 鎵 0x93b6:gē # 鎶 0x93b7:mǎ # 鎷 0x93b8:juān # 鎸 0x93bb:suǒ # 鎻 0x93bf:ná # 鎿 0x93c0:lǔ # 鏀 0x93c1:suǒ # 鏁 0x93c2:ōu # 鏂 0x93c3:zú,chuò # 鏃 0x93c4:tuán # 鏄 0x93c5:xiū,xiù # 鏅 0x93c6:guàn # 鏆 0x93c7:xuàn # 鏇 0x93c8:liàn # 鏈 0x93c9:shòu,sōu # 鏉 0x93ca:ào # 鏊 0x93cb:mǎn # 鏋 0x93cc:mò # 鏌 0x93cd:luó # 鏍 0x93ce:bì # 鏎 0x93cf:wèi # 鏏 0x93d0:liú # 鏐 0x93d1:dí,dī # 鏑 0x93d2:sǎn,qiāo,càn # 鏒 0x93d3:cōng # 鏓 0x93d4:yí # 鏔 0x93d5:lù,áo # 鏕 0x93d6:áo # 鏖 0x93d7:kēng # 鏗 0x93d8:qiāng # 鏘 0x93d9:cuī # 鏙 0x93da:qī # 鏚 0x93db:shǎng # 鏛 0x93dc:tāng,táng # 鏜 0x93dd:màn # 鏝 0x93de:yōng # 鏞 0x93df:chǎn # 鏟 0x93e0:fēng # 鏠 0x93e1:jìng # 鏡 0x93e2:biāo # 鏢 0x93e3:shù # 鏣 0x93e4:lòu # 鏤 0x93e5:xiù # 鏥 0x93e6:cōng # 鏦 0x93e7:lóng # 鏧 0x93e8:zàn # 鏨 0x93e9:jiàn,zàn # 鏩 0x93ea:cáo # 鏪 0x93eb:lí # 鏫 0x93ec:xià # 鏬 0x93ed:xī # 鏭 0x93ee:kāng # 鏮 0x93f0:bèng # 鏰 0x93f3:zhēng # 鏳 0x93f4:lù # 鏴 0x93f5:huá # 鏵 0x93f6:jí # 鏶 0x93f7:pú # 鏷 0x93f8:huì,suì,ruì # 鏸 0x93f9:qiǎng,qiāng # 鏹 0x93fa:pō # 鏺 0x93fb:lín # 鏻 0x93fc:sè # 鏼 0x93fd:xiù # 鏽 0x93fe:sǎn,xiàn,sà # 鏾 0x93ff:chēng # 鏿 0x9400:guì,kuì # 鐀 0x9401:sī # 鐁 0x9402:liú # 鐂 0x9403:náo # 鐃 0x9404:huáng # 鐄 0x9405:piě # 鐅 0x9406:suì # 鐆 0x9407:fán # 鐇 0x9408:qiáo # 鐈 0x9409:quān # 鐉 0x940a:xī # 鐊 0x940b:tàng # 鐋 0x940c:xiàng # 鐌 0x940d:jué # 鐍 0x940e:jiāo # 鐎 0x940f:zūn # 鐏 0x9410:liào # 鐐 0x9411:qì # 鐑 0x9412:láo # 鐒 0x9413:duī # 鐓 0x9414:xín # 鐔 0x9415:zān # 鐕 0x9416:jī # 鐖 0x9417:jiǎn # 鐗 0x9418:zhōng # 鐘 0x9419:dèng # 鐙 0x941a:yā # 鐚 0x941b:yǐng # 鐛 0x941c:duī # 鐜 0x941d:jué # 鐝 0x941e:nòu # 鐞 0x941f:zān # 鐟 0x9420:pǔ # 鐠 0x9421:tiě # 鐡 0x9424:dǐng # 鐤 0x9425:shàn # 鐥 0x9426:kāi # 鐦 0x9427:jiǎn # 鐧 0x9428:fèi # 鐨 0x9429:suì # 鐩 0x942a:lǔ # 鐪 0x942b:juān # 鐫 0x942c:huì # 鐬 0x942d:yù # 鐭 0x942e:lián # 鐮 0x942f:zhuō # 鐯 0x9430:qiāo # 鐰 0x9431:jiàn # 鐱 0x9432:zhuó # 鐲 0x9433:léi # 鐳 0x9434:bì # 鐴 0x9435:tiě # 鐵 0x9436:huán # 鐶 0x9437:yè # 鐷 0x9438:duó # 鐸 0x9439:guò # 鐹 0x943a:dāng,chēng # 鐺 0x943b:jù # 鐻 0x943c:fén # 鐼 0x943d:dá # 鐽 0x943e:bèi # 鐾 0x943f:yì # 鐿 0x9440:ài # 鑀 0x9441:zōng # 鑁 0x9442:xùn # 鑂 0x9443:diào # 鑃 0x9444:zhù # 鑄 0x9445:héng # 鑅 0x9446:zhuì # 鑆 0x9447:jī # 鑇 0x9448:niè # 鑈 0x9449:hé # 鑉 0x944a:huò # 鑊 0x944b:qīng # 鑋 0x944c:bīn # 鑌 0x944d:yīng # 鑍 0x944e:guì # 鑎 0x944f:níng # 鑏 0x9450:xū # 鑐 0x9451:jiàn # 鑑 0x9452:jiàn # 鑒 0x9454:chǎ # 鑔 0x9455:zhì # 鑕 0x9456:miè # 鑖 0x9457:lí # 鑗 0x9458:léi # 鑘 0x9459:jī # 鑙 0x945a:zuān # 鑚 0x945b:kuàng # 鑛 0x945c:shǎng # 鑜 0x945d:péng # 鑝 0x945e:là # 鑞 0x945f:dú # 鑟 0x9460:shuò # 鑠 0x9461:chuò # 鑡 0x9462:lǜ # 鑢 0x9463:biāo # 鑣 0x9464:bào # 鑤 0x9465:lǔ # 鑥 0x9468:lóng # 鑨 0x9469:è # 鑩 0x946a:lú # 鑪 0x946b:xīn # 鑫 0x946c:jiàn # 鑬 0x946d:lán # 鑭 0x946e:bó # 鑮 0x946f:jiān # 鑯 0x9470:yuè,yào # 鑰 0x9471:chán # 鑱 0x9472:xiāng # 鑲 0x9473:jiàn # 鑳 0x9474:xī # 鑴 0x9475:guàn # 鑵 0x9476:cáng # 鑶 0x9477:niè # 鑷 0x9478:lěi # 鑸 0x9479:cuān # 鑹 0x947a:qú # 鑺 0x947b:pàn # 鑻 0x947c:luó # 鑼 0x947d:zuān # 鑽 0x947e:luán # 鑾 0x947f:záo # 鑿 0x9480:niè # 钀 0x9481:jué # 钁 0x9482:tǎng # 钂 0x9483:zhú # 钃 0x9484:làn # 钄 0x9485:jīn # 钅 0x9486:gá # 钆 0x9487:yǐ # 钇 0x9488:zhēn # 针 0x9489:dīng,dìng # 钉 0x948a:zhāo # 钊 0x948b:pō # 钋 0x948c:liǎo,liào # 钌 0x948d:tǔ # 钍 0x948e:qiān # 钎 0x948f:chuàn # 钏 0x9490:shān,shàn # 钐 0x9491:sà,xì # 钑 0x9492:fán # 钒 0x9493:diào # 钓 0x9494:mén # 钔 0x9495:nǚ # 钕 0x9496:yáng # 钖 0x9497:chāi # 钗 0x9498:xíng # 钘 0x9499:gài # 钙 0x949a:bù # 钚 0x949b:tài # 钛 0x949c:jù # 钜 0x949d:dùn # 钝 0x949e:chāo # 钞 0x949f:zhōng # 钟 0x94a0:nà # 钠 0x94a1:bèi # 钡 0x94a2:gāng,gàng # 钢 0x94a3:bǎn # 钣 0x94a4:qián # 钤 0x94a5:yuè,yào # 钥 0x94a6:qīn # 钦 0x94a7:jūn # 钧 0x94a8:wū # 钨 0x94a9:gōu # 钩 0x94aa:kàng # 钪 0x94ab:fāng # 钫 0x94ac:huǒ # 钬 0x94ad:dǒu # 钭 0x94ae:niǔ # 钮 0x94af:bǎ,pá # 钯 0x94b0:yù # 钰 0x94b1:qián # 钱 0x94b2:zhēng,zhèng # 钲 0x94b3:qián # 钳 0x94b4:gǔ # 钴 0x94b5:bō # 钵 0x94b6:kē # 钶 0x94b7:pǒ # 钷 0x94b8:bū # 钸 0x94b9:bó # 钹 0x94ba:yuè # 钺 0x94bb:zuān,zuàn # 钻 0x94bc:mù # 钼 0x94bd:tǎn # 钽 0x94be:jiǎ # 钾 0x94bf:diàn,tián # 钿 0x94c0:yóu # 铀 0x94c1:tiě # 铁 0x94c2:bó # 铂 0x94c3:líng # 铃 0x94c4:shuò # 铄 0x94c5:qiān,yán # 铅 0x94c6:mǎo # 铆 0x94c7:bào,páo # 铇 0x94c8:shì # 铈 0x94c9:xuàn # 铉 0x94ca:tā,tuó # 铊 0x94cb:bì # 铋 0x94cc:ní # 铌 0x94cd:pí,pī # 铍 0x94ce:duó # 铎 0x94cf:xíng # 铏 0x94d0:kào # 铐 0x94d1:lǎo # 铑 0x94d2:ěr # 铒 0x94d3:máng # 铓 0x94d4:yā,yà # 铔 0x94d5:yǒu # 铕 0x94d6:chéng # 铖 0x94d7:jiá # 铗 0x94d8:yé # 铘 0x94d9:náo # 铙 0x94da:zhì # 铚 0x94db:dāng,chēng # 铛 0x94dc:tóng # 铜 0x94dd:lǚ # 铝 0x94de:diào # 铞 0x94df:yīn # 铟 0x94e0:kǎi # 铠 0x94e1:zhá # 铡 0x94e2:zhū # 铢 0x94e3:xiǎn,xǐ # 铣 0x94e4:tǐng,dìng # 铤 0x94e5:diū # 铥 0x94e6:xiān,kuò,tiǎn,guā # 铦 0x94e7:huá # 铧 0x94e8:quán # 铨 0x94e9:shā # 铩 0x94ea:hā,kē # 铪 0x94eb:diào,tiáo,yáo # 铫 0x94ec:gè # 铬 0x94ed:míng # 铭 0x94ee:zhēng # 铮 0x94ef:sè # 铯 0x94f0:jiǎo # 铰 0x94f1:yī # 铱 0x94f2:chǎn # 铲 0x94f3:chòng # 铳 0x94f4:tàng,tāng # 铴 0x94f5:ǎn # 铵 0x94f6:yín # 银 0x94f7:rú # 铷 0x94f8:zhù # 铸 0x94f9:láo # 铹 0x94fa:pū,pù # 铺 0x94fb:wú,yǔ # 铻 0x94fc:lái # 铼 0x94fd:tè # 铽 0x94fe:liàn # 链 0x94ff:kēng # 铿 0x9500:xiāo # 销 0x9501:suǒ # 锁 0x9502:lǐ # 锂 0x9503:zèng # 锃 0x9504:chú # 锄 0x9505:guō # 锅 0x9506:gào # 锆 0x9507:é # 锇 0x9508:xiù # 锈 0x9509:cuò # 锉 0x950a:lüè # 锊 0x950b:fēng # 锋 0x950c:xīn # 锌 0x950d:liǔ # 锍 0x950e:kāi # 锎 0x950f:jiǎn # 锏 0x9510:ruì # 锐 0x9511:tī # 锑 0x9512:láng # 锒 0x9513:qǐn # 锓 0x9514:jū # 锔 0x9515:ā # 锕 0x9516:qiāng # 锖 0x9517:zhě # 锗 0x9518:nuò # 锘 0x9519:cuò # 错 0x951a:máo # 锚 0x951b:bēn # 锛 0x951c:qí # 锜 0x951d:dé # 锝 0x951e:kè # 锞 0x951f:kūn # 锟 0x9520:chāng # 锠 0x9521:xī # 锡 0x9522:gù # 锢 0x9523:luó # 锣 0x9524:chuí # 锤 0x9525:zhuī # 锥 0x9526:jǐn # 锦 0x9527:zhì # 锧 0x9528:xiān # 锨 0x9529:juǎn # 锩 0x952a:huò # 锪 0x952b:péi # 锫 0x952c:tán # 锬 0x952d:dìng # 锭 0x952e:jiàn # 键 0x952f:jù # 锯 0x9530:měng # 锰 0x9531:zī # 锱 0x9532:qiè # 锲 0x9533:yīng # 锳 0x9534:kǎi # 锴 0x9535:qiāng # 锵 0x9536:sī # 锶 0x9537:è # 锷 0x9538:chā # 锸 0x9539:qiāo # 锹 0x953a:zhōng # 锺 0x953b:duàn # 锻 0x953c:sōu # 锼 0x953d:huáng # 锽 0x953e:huán # 锾 0x953f:āi # 锿 0x9540:dù # 镀 0x9541:měi # 镁 0x9542:lòu # 镂 0x9543:zī # 镃 0x9544:fèi # 镄 0x9545:méi # 镅 0x9546:mò # 镆 0x9547:zhèn # 镇 0x9548:bó # 镈 0x9549:gé,lì # 镉 0x954a:niè # 镊 0x954b:tǎng # 镋 0x954c:juān # 镌 0x954d:niè # 镍 0x954e:ná # 镎 0x954f:liú # 镏 0x9550:gǎo,hào # 镐 0x9551:bàng # 镑 0x9552:yì # 镒 0x9553:jiā # 镓 0x9554:bīn # 镔 0x9555:róng # 镕 0x9556:biāo # 镖 0x9557:tāng # 镗 0x9558:màn # 镘 0x9559:luó # 镙 0x955a:bèng # 镚 0x955b:yōng # 镛 0x955c:jìng # 镜 0x955d:dí # 镝 0x955e:zú # 镞 0x955f:xuàn # 镟 0x9560:liú # 镠 0x9561:xín,tán,chán # 镡 0x9562:jué # 镢 0x9563:liào # 镣 0x9564:pú # 镤 0x9565:lǔ # 镥 0x9566:duī # 镦 0x9567:lán # 镧 0x9568:pǔ # 镨 0x9569:cuān # 镩 0x956a:qiǎng # 镪 0x956b:dèng # 镫 0x956c:huò # 镬 0x956d:léi # 镭 0x956e:huán # 镮 0x956f:zhuó # 镯 0x9570:lián # 镰 0x9571:yì # 镱 0x9572:chǎ # 镲 0x9573:biāo # 镳 0x9574:là # 镴 0x9575:chán # 镵 0x9576:xiāng # 镶 0x9577:cháng,zhǎng # 長 0x9578:cháng # 镸 0x9579:jiǔ # 镹 0x957a:ǎo # 镺 0x957b:dié # 镻 0x957c:jié # 镼 0x957d:liǎo # 镽 0x957e:mí # 镾 0x957f:cháng,zhǎng # 长 0x9580:mén # 門 0x9581:mà # 閁 0x9582:shuān # 閂 0x9583:shǎn # 閃 0x9584:huò,shǎn # 閄 0x9585:mén # 閅 0x9586:yán # 閆 0x9587:bì # 閇 0x9588:hàn,bì # 閈 0x9589:bì # 閉 0x958b:kāi # 開 0x958c:kāng,kàng # 閌 0x958d:bēng # 閍 0x958e:hóng # 閎 0x958f:rùn # 閏 0x9590:sàn # 閐 0x9591:xián # 閑 0x9592:xián,jiān,jiàn # 閒 0x9593:jiān,jiàn # 間 0x9594:mǐn # 閔 0x9595:xiā,xiǎ # 閕 0x9597:dòu # 閗 0x9598:zhá # 閘 0x9599:nào # 閙 0x959b:pēng,pèng # 閛 0x959c:xiǎ,kě # 閜 0x959d:líng # 閝 0x959e:biàn,guān # 閞 0x959f:bì # 閟 0x95a0:rùn # 閠 0x95a1:hé # 閡 0x95a2:guān # 関 0x95a3:gé # 閣 0x95a4:hé,gé # 閤 0x95a5:fá # 閥 0x95a6:chù # 閦 0x95a7:hòng,xiàng # 閧 0x95a8:guī # 閨 0x95a9:mǐn # 閩 0x95ab:kǔn # 閫 0x95ac:làng # 閬 0x95ad:lǘ # 閭 0x95ae:tíng,tǐng # 閮 0x95af:shà # 閯 0x95b0:jú # 閰 0x95b1:yuè # 閱 0x95b2:yuè # 閲 0x95b3:chǎn # 閳 0x95b4:qù # 閴 0x95b5:lìn # 閵 0x95b6:chāng # 閶 0x95b7:shā # 閷 0x95b8:kǔn # 閸 0x95b9:yān # 閹 0x95ba:wén # 閺 0x95bb:yán # 閻 0x95bc:è,yān # 閼 0x95bd:hūn # 閽 0x95be:yù # 閾 0x95bf:wén # 閿 0x95c0:hòng # 闀 0x95c1:bāo # 闁 0x95c2:hòng,juǎn,xiàng # 闂 0x95c3:qù # 闃 0x95c4:yǎo # 闄 0x95c5:wén # 闅 0x95c6:bǎn,pàn # 闆 0x95c7:àn # 闇 0x95c8:wéi # 闈 0x95c9:yīn # 闉 0x95ca:kuò # 闊 0x95cb:què # 闋 0x95cc:lán # 闌 0x95cd:dū,shé # 闍 0x95d0:tián # 闐 0x95d1:niè # 闑 0x95d2:tà # 闒 0x95d3:kǎi # 闓 0x95d4:hé # 闔 0x95d5:què,quē # 闕 0x95d6:chuǎng # 闖 0x95d7:guān # 闗 0x95d8:dòu # 闘 0x95d9:qǐ # 闙 0x95da:kuī # 闚 0x95db:táng,tāng,chāng # 闛 0x95dc:guān # 關 0x95dd:piáo # 闝 0x95de:kàn,hǎn # 闞 0x95df:xì,sè,tà # 闟 0x95e0:huì # 闠 0x95e1:chǎn # 闡 0x95e2:pì # 闢 0x95e3:dāng,dàng # 闣 0x95e4:huán # 闤 0x95e5:tà # 闥 0x95e6:wén # 闦 0x95e8:mén # 门 0x95e9:shuān # 闩 0x95ea:shǎn # 闪 0x95eb:yán # 闫 0x95ec:hàn,bì # 闬 0x95ed:bì # 闭 0x95ee:wèn # 问 0x95ef:chuǎng # 闯 0x95f0:rùn # 闰 0x95f1:wéi # 闱 0x95f2:xián # 闲 0x95f3:hóng # 闳 0x95f4:jiān,jiàn # 间 0x95f5:mǐn # 闵 0x95f6:kàng,kāng # 闶 0x95f7:mèn,mēn # 闷 0x95f8:zhá # 闸 0x95f9:nào # 闹 0x95fa:guī # 闺 0x95fb:wén # 闻 0x95fc:tà # 闼 0x95fd:mǐn # 闽 0x95fe:lǘ # 闾 0x95ff:kǎi # 闿 0x9600:fá # 阀 0x9601:gé # 阁 0x9602:hé # 阂 0x9603:kǔn # 阃 0x9604:jiū # 阄 0x9605:yuè # 阅 0x9606:làng # 阆 0x9607:dū,shé # 阇 0x9608:yù # 阈 0x9609:yān # 阉 0x960a:chāng # 阊 0x960b:xì # 阋 0x960c:wén # 阌 0x960d:hūn # 阍 0x960e:yán # 阎 0x960f:è,yān # 阏 0x9610:chǎn # 阐 0x9611:lán # 阑 0x9612:qù # 阒 0x9613:huì # 阓 0x9614:kuò # 阔 0x9615:què # 阕 0x9616:hé # 阖 0x9617:tián # 阗 0x9618:tà # 阘 0x9619:quē,què # 阙 0x961a:kàn # 阚 0x961b:huán # 阛 0x961c:fù # 阜 0x961d:fǔ # 阝 0x961e:lè # 阞 0x961f:duì # 队 0x9620:xìn # 阠 0x9621:qiān # 阡 0x9622:wù # 阢 0x9623:yì # 阣 0x9624:tuó # 阤 0x9625:yīn # 阥 0x9626:yáng # 阦 0x9627:dǒu # 阧 0x9628:è # 阨 0x9629:shēng # 阩 0x962a:bǎn # 阪 0x962b:péi # 阫 0x962c:kēng # 阬 0x962d:yǔn # 阭 0x962e:ruǎn # 阮 0x962f:zhǐ # 阯 0x9630:pí # 阰 0x9631:jǐng # 阱 0x9632:fáng # 防 0x9633:yáng # 阳 0x9634:yīn # 阴 0x9635:zhèn # 阵 0x9636:jiē # 阶 0x9637:chēng # 阷 0x9638:è # 阸 0x9639:qū # 阹 0x963a:dǐ # 阺 0x963b:zǔ # 阻 0x963c:zuò # 阼 0x963d:diàn,yán # 阽 0x963e:lín # 阾 0x963f:ā,ē # 阿 0x9640:tuó # 陀 0x9641:tuó # 陁 0x9642:bēi,pí,pō # 陂 0x9643:bǐng # 陃 0x9644:fù # 附 0x9645:jì # 际 0x9646:lù,liù # 陆 0x9647:lǒng # 陇 0x9648:chén # 陈 0x9649:xíng # 陉 0x964a:duò # 陊 0x964b:lòu # 陋 0x964c:mò # 陌 0x964d:jiàng,xiáng # 降 0x964e:shū # 陎 0x964f:duò # 陏 0x9650:xiàn # 限 0x9651:ér # 陑 0x9652:guǐ # 陒 0x9653:yū # 陓 0x9654:gāi # 陔 0x9655:shǎn # 陕 0x9656:jùn # 陖 0x9657:qiào # 陗 0x9658:xíng # 陘 0x9659:chún # 陙 0x965a:wǔ # 陚 0x965b:bì # 陛 0x965c:xiá # 陜 0x965d:shǎn # 陝 0x965e:shēng # 陞 0x965f:zhì # 陟 0x9660:pū # 陠 0x9661:dǒu # 陡 0x9662:yuàn # 院 0x9663:zhèn # 陣 0x9664:chú # 除 0x9665:xiàn # 陥 0x9667:niè # 陧 0x9668:yǔn # 陨 0x9669:xiǎn # 险 0x966a:péi # 陪 0x966b:fèi # 陫 0x966c:zōu # 陬 0x966d:qí,yī # 陭 0x966e:duì # 陮 0x966f:lún # 陯 0x9670:yīn # 陰 0x9671:jū # 陱 0x9672:chuí # 陲 0x9673:chén # 陳 0x9674:pī # 陴 0x9675:líng # 陵 0x9676:táo,yáo # 陶 0x9677:xiàn # 陷 0x9678:lù # 陸 0x967a:xiǎn # 険 0x967b:yīn # 陻 0x967c:zhǔ # 陼 0x967d:yáng # 陽 0x967e:réng # 陾 0x967f:xiá # 陿 0x9680:chóng # 隀 0x9681:yàn,yǎn # 隁 0x9682:yīn # 隂 0x9683:yú,yáo,shù # 隃 0x9684:dī # 隄 0x9685:yú # 隅 0x9686:lóng # 隆 0x9687:wēi # 隇 0x9688:wēi # 隈 0x9689:niè # 隉 0x968a:duì,zhuì # 隊 0x968b:suí,duò # 隋 0x968c:àn # 隌 0x968d:huáng # 隍 0x968e:jiē # 階 0x968f:suí # 随 0x9690:yǐn,yìn # 隐 0x9691:qí,gāi,ái # 隑 0x9692:yǎn # 隒 0x9693:huī,duò # 隓 0x9694:gé # 隔 0x9695:yǔn # 隕 0x9696:wù # 隖 0x9697:wěi,kuí # 隗 0x9698:ài # 隘 0x9699:xì # 隙 0x969a:táng # 隚 0x969b:jì # 際 0x969c:zhàng # 障 0x969d:dǎo # 隝 0x969e:áo # 隞 0x969f:xì # 隟 0x96a0:yǐn,yìn # 隠 0x96a2:rǎo # 隢 0x96a3:lín # 隣 0x96a4:tuí # 隤 0x96a5:dèng # 隥 0x96a6:pí # 隦 0x96a7:suì # 隧 0x96a8:suí # 隨 0x96a9:ào,yù # 隩 0x96aa:xiǎn # 險 0x96ab:fén # 隫 0x96ac:nǐ # 隬 0x96ad:ér # 隭 0x96ae:jī # 隮 0x96af:dǎo # 隯 0x96b0:xí # 隰 0x96b1:yǐn,yìn # 隱 0x96b2:zhì # 隲 0x96b3:huī,duò # 隳 0x96b4:lǒng # 隴 0x96b5:xī # 隵 0x96b6:lì # 隶 0x96b7:lì # 隷 0x96b8:lì # 隸 0x96b9:zhuī,cuī,wéi # 隹 0x96ba:hú,hè # 隺 0x96bb:zhī # 隻 0x96bc:sǔn # 隼 0x96bd:jùn,juàn # 隽 0x96be:nán,nàn,nuó # 难 0x96bf:yì # 隿 0x96c0:què,qiāo,qiǎo # 雀 0x96c1:yàn # 雁 0x96c2:qín # 雂 0x96c3:jiān # 雃 0x96c4:xióng # 雄 0x96c5:yǎ # 雅 0x96c6:jí # 集 0x96c7:gù # 雇 0x96c8:huán # 雈 0x96c9:zhì # 雉 0x96ca:gòu # 雊 0x96cb:jùn,juàn # 雋 0x96cc:cí # 雌 0x96cd:yōng # 雍 0x96ce:jū # 雎 0x96cf:chú # 雏 0x96d0:hū # 雐 0x96d1:zá # 雑 0x96d2:luò # 雒 0x96d3:yú # 雓 0x96d4:chóu # 雔 0x96d5:diāo # 雕 0x96d6:suī # 雖 0x96d7:hàn # 雗 0x96d8:huò # 雘 0x96d9:shuāng # 雙 0x96da:guàn,huán # 雚 0x96db:chú # 雛 0x96dc:zá # 雜 0x96dd:yōng # 雝 0x96de:jī # 雞 0x96df:guī,xī # 雟 0x96e0:chóu # 雠 0x96e1:liù # 雡 0x96e2:lí # 離 0x96e3:nán,nàn,nuó # 難 0x96e4:yù,xué # 雤 0x96e5:zá # 雥 0x96e6:chóu # 雦 0x96e7:jí # 雧 0x96e8:yǔ,yù # 雨 0x96e9:yú # 雩 0x96ea:xuě # 雪 0x96eb:nǎ # 雫 0x96ec:fǒu # 雬 0x96ed:sè,xí # 雭 0x96ee:mù # 雮 0x96ef:wén # 雯 0x96f0:fēn # 雰 0x96f1:pāng # 雱 0x96f2:yún # 雲 0x96f3:lì # 雳 0x96f4:chì # 雴 0x96f5:yāng # 雵 0x96f6:líng # 零 0x96f7:léi # 雷 0x96f8:án # 雸 0x96f9:báo # 雹 0x96fa:wù,méng # 雺 0x96fb:diàn # 電 0x96fc:dàng # 雼 0x96fd:hū,hù # 雽 0x96fe:wù # 雾 0x96ff:diào # 雿 0x9700:xū # 需 0x9701:jì # 霁 0x9702:mù # 霂 0x9703:chén # 霃 0x9704:xiāo # 霄 0x9705:zhá # 霅 0x9706:tíng # 霆 0x9707:zhèn # 震 0x9708:pèi # 霈 0x9709:méi # 霉 0x970a:líng # 霊 0x970b:qī # 霋 0x970c:zhōu # 霌 0x970d:huò # 霍 0x970e:shà # 霎 0x970f:fēi # 霏 0x9710:hóng # 霐 0x9711:zhān # 霑 0x9712:yīn # 霒 0x9713:ní # 霓 0x9714:shù # 霔 0x9715:tún # 霕 0x9716:lín # 霖 0x9718:dòng # 霘 0x9719:yīng # 霙 0x971a:wù # 霚 0x971b:líng # 霛 0x971c:shuāng # 霜 0x971d:líng # 霝 0x971e:xiá # 霞 0x971f:hóng # 霟 0x9720:yīn # 霠 0x9721:mài # 霡 0x9722:mài # 霢 0x9723:yǔn # 霣 0x9724:liù # 霤 0x9725:mèng # 霥 0x9726:bīn # 霦 0x9727:wù # 霧 0x9728:wèi # 霨 0x9729:kuò # 霩 0x972a:yín # 霪 0x972b:xí # 霫 0x972c:yì # 霬 0x972d:ǎi # 霭 0x972e:dàn # 霮 0x972f:tèng # 霯 0x9730:xiàn # 霰 0x9731:yù # 霱 0x9732:lòu,lù # 露 0x9733:lóng # 霳 0x9734:dài # 霴 0x9735:jí # 霵 0x9736:pāng # 霶 0x9737:yáng # 霷 0x9738:bà # 霸 0x9739:pī # 霹 0x973a:wēi # 霺 0x973c:xì # 霼 0x973d:jì # 霽 0x973e:mái # 霾 0x973f:méng # 霿 0x9740:méng # 靀 0x9741:léi # 靁 0x9742:lì # 靂 0x9743:huò # 靃 0x9744:ǎi # 靄 0x9745:fèi # 靅 0x9746:dài # 靆 0x9747:lóng # 靇 0x9748:lìng # 靈 0x9749:ài # 靉 0x974a:fēng # 靊 0x974b:lì # 靋 0x974c:bǎo # 靌 0x974e:hè # 靎 0x974f:hè # 靏 0x9750:bìng # 靐 0x9751:qīng # 靑 0x9752:qīng # 青 0x9753:jìng,liàng # 靓 0x9754:tiān # 靔 0x9755:zhèng # 靕 0x9756:jìng # 靖 0x9757:chēng # 靗 0x9758:qìng # 靘 0x9759:jìng # 静 0x975a:jìng,liàng # 靚 0x975b:diàn # 靛 0x975c:jìng # 靜 0x975d:tiān # 靝 0x975e:fēi # 非 0x975f:fēi # 靟 0x9760:kào # 靠 0x9761:mí # 靡 0x9762:miàn # 面 0x9763:miàn # 靣 0x9764:pào # 靤 0x9765:yè # 靥 0x9766:miǎn # 靦 0x9767:huì # 靧 0x9768:yè # 靨 0x9769:gé,jí # 革 0x976a:dīng # 靪 0x976b:chá # 靫 0x976c:jiān # 靬 0x976d:rèn # 靭 0x976e:dí # 靮 0x976f:dù # 靯 0x9770:wù # 靰 0x9771:rèn # 靱 0x9772:qín # 靲 0x9773:jìn # 靳 0x9774:xuē # 靴 0x9775:niǔ # 靵 0x9776:bǎ # 靶 0x9777:yǐn # 靷 0x9778:sǎ # 靸 0x9779:nà # 靹 0x977a:mò # 靺 0x977b:zǔ # 靻 0x977c:dá # 靼 0x977d:bàn # 靽 0x977e:xiè # 靾 0x977f:yào # 靿 0x9780:táo # 鞀 0x9781:bèi # 鞁 0x9782:jiē # 鞂 0x9783:hóng # 鞃 0x9784:páo # 鞄 0x9785:yāng,yàng # 鞅 0x9787:yīn # 鞇 0x9788:gé,tà,sǎ # 鞈 0x9789:táo # 鞉 0x978a:jié,jí # 鞊 0x978b:xié # 鞋 0x978c:ān # 鞌 0x978d:ān # 鞍 0x978e:hén # 鞎 0x978f:gǒng # 鞏 0x9791:dá # 鞑 0x9792:qiáo # 鞒 0x9793:tīng # 鞓 0x9794:mán,mèn # 鞔 0x9795:biān,yìng # 鞕 0x9796:suī # 鞖 0x9797:tiáo # 鞗 0x9798:qiào,shāo # 鞘 0x9799:xuān,juān # 鞙 0x979a:kòng # 鞚 0x979b:běng # 鞛 0x979c:tà # 鞜 0x979d:shàng,zhǎng # 鞝 0x979e:bǐng,pí,bì,bēi # 鞞 0x979f:kuò # 鞟 0x97a0:jū # 鞠 0x97a1:la # 鞡 0x97a2:xiè,dié # 鞢 0x97a3:róu # 鞣 0x97a4:bāng # 鞤 0x97a5:ēng # 鞥 0x97a6:qiū # 鞦 0x97a7:qiū # 鞧 0x97a8:hé # 鞨 0x97a9:qiào # 鞩 0x97aa:mù,móu # 鞪 0x97ab:jū # 鞫 0x97ac:jiàn,jiān # 鞬 0x97ad:biān # 鞭 0x97ae:dī # 鞮 0x97af:jiān # 鞯 0x97b1:tāo # 鞱 0x97b2:gōu # 鞲 0x97b3:tà # 鞳 0x97b4:bèi # 鞴 0x97b5:xié # 鞵 0x97b6:pán # 鞶 0x97b7:gé # 鞷 0x97b8:bì,bǐng # 鞸 0x97b9:kuò # 鞹 0x97bb:lóu # 鞻 0x97bc:guì # 鞼 0x97bd:qiáo # 鞽 0x97be:xuē # 鞾 0x97bf:jī # 鞿 0x97c0:jiān # 韀 0x97c1:jiāng # 韁 0x97c2:chàn # 韂 0x97c3:dá # 韃 0x97c4:huò # 韄 0x97c5:xiǎn # 韅 0x97c6:qiān # 韆 0x97c7:dú # 韇 0x97c8:wā # 韈 0x97c9:jiān # 韉 0x97ca:lán # 韊 0x97cb:wéi # 韋 0x97cc:rèn # 韌 0x97cd:fú # 韍 0x97ce:mèi,wà # 韎 0x97cf:quàn # 韏 0x97d0:gé # 韐 0x97d1:wěi # 韑 0x97d2:qiào # 韒 0x97d3:hán # 韓 0x97d4:chàng # 韔 0x97d6:rǒu # 韖 0x97d7:yùn # 韗 0x97d8:shè,xiè # 韘 0x97d9:wěi # 韙 0x97da:gé # 韚 0x97db:bài # 韛 0x97dc:tāo # 韜 0x97dd:gōu # 韝 0x97de:yùn # 韞 0x97e0:bì # 韠 0x97e1:wěi # 韡 0x97e2:suì # 韢 0x97e3:dú # 韣 0x97e4:wà # 韤 0x97e5:dú # 韥 0x97e6:wéi # 韦 0x97e7:rèn # 韧 0x97e8:fú # 韨 0x97e9:hán # 韩 0x97ea:wěi # 韪 0x97eb:yùn,wēn # 韫 0x97ec:tāo # 韬 0x97ed:jiǔ # 韭 0x97ee:jiǔ # 韮 0x97ef:xiān # 韯 0x97f0:xiè # 韰 0x97f1:xiān # 韱 0x97f2:jī # 韲 0x97f3:yīn # 音 0x97f4:zá # 韴 0x97f5:yùn # 韵 0x97f6:sháo # 韶 0x97f7:lè # 韷 0x97f8:péng # 韸 0x97f9:huáng # 韹 0x97fa:yīng # 韺 0x97fb:yùn # 韻 0x97fc:péng # 韼 0x97fd:ān # 韽 0x97fe:yīn # 韾 0x97ff:xiǎng # 響 0x9800:hù # 頀 0x9801:yè # 頁 0x9802:dǐng # 頂 0x9803:qǐng # 頃 0x9804:qiú # 頄 0x9805:xiàng # 項 0x9806:shùn # 順 0x9807:hān # 頇 0x9808:xū # 須 0x9809:yí # 頉 0x980a:xū # 頊 0x980b:ě # 頋 0x980c:sòng # 頌 0x980d:kuǐ # 頍 0x980e:qí # 頎 0x980f:háng # 頏 0x9810:yù # 預 0x9811:wán # 頑 0x9812:bān # 頒 0x9813:dùn # 頓 0x9814:dí # 頔 0x9815:dān # 頕 0x9816:pàn # 頖 0x9817:pō # 頗 0x9818:lǐng # 領 0x9819:chè # 頙 0x981a:jǐng # 頚 0x981b:lèi # 頛 0x981c:hé # 頜 0x981d:qiāo # 頝 0x981e:è # 頞 0x981f:é # 頟 0x9820:wěi # 頠 0x9821:jié # 頡 0x9822:kuò # 頢 0x9823:shěn # 頣 0x9824:yí # 頤 0x9825:yí # 頥 0x9826:kē # 頦 0x9827:duǐ # 頧 0x9828:yǔ # 頨 0x9829:pīng # 頩 0x982a:lèi # 頪 0x982b:fǔ # 頫 0x982c:jiá # 頬 0x982d:tóu # 頭 0x982e:huì # 頮 0x982f:kuí # 頯 0x9830:jiá # 頰 0x9831:luō # 頱 0x9832:tǐng # 頲 0x9833:chēng # 頳 0x9834:yǐng # 頴 0x9835:jūn # 頵 0x9836:hú # 頶 0x9837:hàn # 頷 0x9838:jǐng # 頸 0x9839:tuí # 頹 0x983a:tuí # 頺 0x983b:bīn,pín # 頻 0x983c:lài # 頼 0x983d:tuí # 頽 0x983e:zī # 頾 0x983f:zī # 頿 0x9840:chuí # 顀 0x9841:dìng # 顁 0x9842:lài # 顂 0x9843:tán # 顃 0x9844:hàn # 顄 0x9845:qiān # 顅 0x9846:kē # 顆 0x9847:cuì # 顇 0x9848:jiǒng # 顈 0x9849:qīn # 顉 0x984a:yí # 顊 0x984b:sāi # 顋 0x984c:tí # 題 0x984d:é # 額 0x984e:è # 顎 0x984f:yán # 顏 0x9850:wèn # 顐 0x9851:kǎn # 顑 0x9852:yóng # 顒 0x9853:zhuān # 顓 0x9854:yán # 顔 0x9855:xiǎn # 顕 0x9856:xìn # 顖 0x9857:yǐ # 顗 0x9858:yuàn # 願 0x9859:sǎng # 顙 0x985a:diān # 顚 0x985b:diān # 顛 0x985c:jiǎng # 顜 0x985d:kuī # 顝 0x985e:lèi # 類 0x985f:láo # 顟 0x9860:piǎo # 顠 0x9861:wài # 顡 0x9862:mān # 顢 0x9863:cù # 顣 0x9864:yáo # 顤 0x9865:hào # 顥 0x9866:qiáo # 顦 0x9867:gù # 顧 0x9868:xùn # 顨 0x9869:yǎn # 顩 0x986a:huì # 顪 0x986b:chàn,zhàn,shān # 顫 0x986c:rú # 顬 0x986d:méng # 顭 0x986e:bīn # 顮 0x986f:xiǎn # 顯 0x9870:pín # 顰 0x9871:lú # 顱 0x9872:lǎn # 顲 0x9873:niè # 顳 0x9874:quán # 顴 0x9875:yè # 页 0x9876:dǐng # 顶 0x9877:qǐng # 顷 0x9878:hān # 顸 0x9879:xiàng # 项 0x987a:shùn # 顺 0x987b:xū # 须 0x987c:xū # 顼 0x987d:wán # 顽 0x987e:gù # 顾 0x987f:dùn,dú # 顿 0x9880:qí # 颀 0x9881:bān # 颁 0x9882:sòng # 颂 0x9883:háng # 颃 0x9884:yù # 预 0x9885:lú # 颅 0x9886:lǐng # 领 0x9887:pō # 颇 0x9888:jǐng,gěng # 颈 0x9889:jié,xié,jiá # 颉 0x988a:jiá # 颊 0x988b:tǐng # 颋 0x988c:hé,gé # 颌 0x988d:yǐng # 颍 0x988e:jiǒng # 颎 0x988f:kē # 颏 0x9890:yí # 颐 0x9891:pín,bīn # 频 0x9892:huì # 颒 0x9893:tuí # 颓 0x9894:hàn # 颔 0x9895:yǐng # 颕 0x9896:yǐng # 颖 0x9897:kē # 颗 0x9898:tí # 题 0x9899:yóng # 颙 0x989a:è # 颚 0x989b:zhuān # 颛 0x989c:yán # 颜 0x989d:é # 额 0x989e:niè # 颞 0x989f:mān # 颟 0x98a0:diān # 颠 0x98a1:sǎng # 颡 0x98a2:hào # 颢 0x98a3:lèi # 颣 0x98a4:chàn,zhàn # 颤 0x98a5:rú # 颥 0x98a6:pín # 颦 0x98a7:quán # 颧 0x98a8:fēng,fěng # 風 0x98a9:biāo,diū # 颩 0x98ab:fú # 颫 0x98ac:xiā # 颬 0x98ad:zhǎn # 颭 0x98ae:biāo # 颮 0x98af:sà # 颯 0x98b0:bá,fú # 颰 0x98b1:tái # 颱 0x98b2:liè # 颲 0x98b3:guā # 颳 0x98b4:xuàn # 颴 0x98b5:xiāo # 颵 0x98b6:jù # 颶 0x98b7:biāo # 颷 0x98b8:sī # 颸 0x98b9:wěi # 颹 0x98ba:yáng # 颺 0x98bb:yáo # 颻 0x98bc:sōu # 颼 0x98bd:kǎi # 颽 0x98be:sāo,sōu # 颾 0x98bf:fān # 颿 0x98c0:liú # 飀 0x98c1:xí # 飁 0x98c2:liù,liáo # 飂 0x98c3:piāo # 飃 0x98c4:piāo # 飄 0x98c5:liú # 飅 0x98c6:biāo # 飆 0x98c7:biāo # 飇 0x98c8:biāo # 飈 0x98c9:liáo # 飉 0x98cb:sè # 飋 0x98cc:fēng # 飌 0x98cd:xiū # 飍 0x98ce:fēng,fěng # 风 0x98cf:yáng # 飏 0x98d0:zhǎn # 飐 0x98d1:biāo # 飑 0x98d2:sà # 飒 0x98d3:jù # 飓 0x98d4:sī # 飔 0x98d5:sōu # 飕 0x98d6:yáo # 飖 0x98d7:liú # 飗 0x98d8:piāo # 飘 0x98d9:biāo # 飙 0x98da:biāo # 飚 0x98db:fēi # 飛 0x98dc:fān # 飜 0x98dd:fēi # 飝 0x98de:fēi # 飞 0x98df:shí,sì,yì # 食 0x98e0:shí # 飠 0x98e1:cān # 飡 0x98e2:jī # 飢 0x98e3:dìng # 飣 0x98e4:sì # 飤 0x98e5:tuō # 飥 0x98e6:zhān # 飦 0x98e7:sūn # 飧 0x98e8:xiǎng # 飨 0x98e9:tún # 飩 0x98ea:rèn # 飪 0x98eb:yù # 飫 0x98ec:yǎng,juàn # 飬 0x98ed:chì # 飭 0x98ee:yǐn,yìn # 飮 0x98ef:fàn # 飯 0x98f0:fàn # 飰 0x98f1:sūn # 飱 0x98f2:yǐn,yìn # 飲 0x98f3:zhù,tǒu # 飳 0x98f4:yí,sì # 飴 0x98f5:zuò,zé,zhā # 飵 0x98f6:bì # 飶 0x98f7:jiě # 飷 0x98f8:tāo # 飸 0x98f9:bǎo # 飹 0x98fa:cí # 飺 0x98fb:tiè # 飻 0x98fc:sì # 飼 0x98fd:bǎo # 飽 0x98fe:shì # 飾 0x98ff:duò # 飿 0x9900:hài # 餀 0x9901:rèn # 餁 0x9902:tiǎn # 餂 0x9903:jiǎo # 餃 0x9904:hé # 餄 0x9905:bǐng # 餅 0x9906:yáo # 餆 0x9907:tóng # 餇 0x9908:cí # 餈 0x9909:xiǎng # 餉 0x990a:yǎng # 養 0x990b:juàn # 餋 0x990c:ěr # 餌 0x990d:yàn # 餍 0x990e:lè # 餎 0x990f:xī # 餏 0x9910:cān # 餐 0x9911:bō # 餑 0x9912:něi # 餒 0x9913:è # 餓 0x9914:bū # 餔 0x9915:jùn # 餕 0x9916:dòu # 餖 0x9917:sù # 餗 0x9918:yú # 餘 0x9919:shì # 餙 0x991a:yáo # 餚 0x991b:hún # 餛 0x991c:guǒ # 餜 0x991d:shì # 餝 0x991e:jiàn # 餞 0x991f:chuò # 餟 0x9920:bǐng # 餠 0x9921:xiàn # 餡 0x9922:bù # 餢 0x9923:yè # 餣 0x9924:dàn # 餤 0x9925:fēi # 餥 0x9926:zhāng # 餦 0x9927:wèi # 餧 0x9928:guǎn # 館 0x9929:è # 餩 0x992a:nuǎn # 餪 0x992b:yùn # 餫 0x992c:hú # 餬 0x992d:huáng # 餭 0x992e:tiè # 餮 0x992f:huì # 餯 0x9930:jiān # 餰 0x9931:hóu # 餱 0x9932:ài # 餲 0x9933:xíng # 餳 0x9934:fēn # 餴 0x9935:wèi # 餵 0x9936:gǔ # 餶 0x9937:chā # 餷 0x9938:sòng # 餸 0x9939:táng # 餹 0x993a:bó # 餺 0x993b:gāo # 餻 0x993c:xì # 餼 0x993d:kuì # 餽 0x993e:liù # 餾 0x993f:sōu # 餿 0x9940:táo # 饀 0x9941:yè # 饁 0x9942:wēn # 饂 0x9943:mó # 饃 0x9944:táng # 饄 0x9945:mán # 饅 0x9946:bì # 饆 0x9947:yù # 饇 0x9948:xiū # 饈 0x9949:jǐn # 饉 0x994a:sǎn # 饊 0x994b:kuì # 饋 0x994c:zhuàn # 饌 0x994d:shàn # 饍 0x994e:xī # 饎 0x994f:dàn # 饏 0x9950:yì # 饐 0x9951:jī # 饑 0x9952:ráo # 饒 0x9953:chēng # 饓 0x9954:yōng # 饔 0x9955:tāo # 饕 0x9956:wèi # 饖 0x9957:xiǎng # 饗 0x9958:zhān # 饘 0x9959:fēn # 饙 0x995a:hài # 饚 0x995b:méng # 饛 0x995c:yàn # 饜 0x995d:mó # 饝 0x995e:chán # 饞 0x995f:xiǎng,náng # 饟 0x9960:luó # 饠 0x9961:zàn # 饡 0x9962:náng # 饢 0x9963:shí # 饣 0x9964:dìng # 饤 0x9965:jī # 饥 0x9966:tuō # 饦 0x9967:xíng # 饧 0x9968:tún # 饨 0x9969:xì # 饩 0x996a:rèn # 饪 0x996b:yù # 饫 0x996c:chì # 饬 0x996d:fàn # 饭 0x996e:yǐn # 饮 0x996f:jiàn # 饯 0x9970:shì # 饰 0x9971:bǎo # 饱 0x9972:sì # 饲 0x9973:duò # 饳 0x9974:yí # 饴 0x9975:ěr # 饵 0x9976:ráo # 饶 0x9977:xiǎng # 饷 0x9978:hé # 饸 0x9979:gē,le # 饹 0x997a:jiǎo # 饺 0x997b:xī # 饻 0x997c:bǐng # 饼 0x997d:bō # 饽 0x997e:dòu # 饾 0x997f:è # 饿 0x9980:yú # 馀 0x9981:něi # 馁 0x9982:jùn # 馂 0x9983:guǒ # 馃 0x9984:hún # 馄 0x9985:xiàn # 馅 0x9986:guǎn # 馆 0x9987:chā # 馇 0x9988:kuì # 馈 0x9989:gǔ # 馉 0x998a:sōu # 馊 0x998b:chán # 馋 0x998c:yè # 馌 0x998d:mó # 馍 0x998e:bó # 馎 0x998f:liù,liú # 馏 0x9990:xiū # 馐 0x9991:jǐn # 馑 0x9992:mán # 馒 0x9993:sǎn # 馓 0x9994:zhuàn # 馔 0x9995:náng,nǎng # 馕 0x9996:shǒu # 首 0x9997:kuí # 馗 0x9998:guó # 馘 0x9999:xiāng # 香 0x999a:fēn # 馚 0x999b:bó # 馛 0x999c:ní # 馜 0x999d:bì # 馝 0x999e:bó # 馞 0x999f:tú # 馟 0x99a0:hān # 馠 0x99a1:fēi # 馡 0x99a2:jiān # 馢 0x99a3:ān # 馣 0x99a4:ài # 馤 0x99a5:fù # 馥 0x99a6:xiān # 馦 0x99a7:yūn,wò # 馧 0x99a8:xīn # 馨 0x99a9:fén # 馩 0x99aa:pīn # 馪 0x99ab:xīn # 馫 0x99ac:mǎ # 馬 0x99ad:yù # 馭 0x99ae:féng,píng # 馮 0x99af:hàn,hán # 馯 0x99b0:dí # 馰 0x99b1:tuó,duò # 馱 0x99b2:tuō,zhé # 馲 0x99b3:chí # 馳 0x99b4:xùn # 馴 0x99b5:zhù # 馵 0x99b6:zhī,shì # 馶 0x99b7:pèi # 馷 0x99b8:xìn,jìn # 馸 0x99b9:rì # 馹 0x99ba:sà # 馺 0x99bb:yǔn # 馻 0x99bc:wén # 馼 0x99bd:zhí # 馽 0x99be:dǎn,dàn # 馾 0x99bf:lú # 馿 0x99c0:yóu # 駀 0x99c1:bó # 駁 0x99c2:bǎo # 駂 0x99c3:jué,kuài # 駃 0x99c4:tuó,duò # 駄 0x99c5:yì # 駅 0x99c6:qū # 駆 0x99c8:qū # 駈 0x99c9:jiōng # 駉 0x99ca:pǒ # 駊 0x99cb:zhāo # 駋 0x99cc:yuān # 駌 0x99cd:pēng # 駍 0x99ce:zhòu # 駎 0x99cf:jù # 駏 0x99d0:zhù # 駐 0x99d1:nú # 駑 0x99d2:jū # 駒 0x99d3:pī # 駓 0x99d4:zǎng # 駔 0x99d5:jià # 駕 0x99d6:líng # 駖 0x99d7:zhěn # 駗 0x99d8:tái,dài # 駘 0x99d9:fù # 駙 0x99da:yǎng # 駚 0x99db:shǐ # 駛 0x99dc:bì # 駜 0x99dd:tuó # 駝 0x99de:tuó # 駞 0x99df:sì # 駟 0x99e0:liú # 駠 0x99e1:mà # 駡 0x99e2:pián # 駢 0x99e3:táo # 駣 0x99e4:zhì # 駤 0x99e5:róng # 駥 0x99e6:téng # 駦 0x99e7:dòng # 駧 0x99e8:xún,xuān # 駨 0x99e9:quán # 駩 0x99ea:shēn # 駪 0x99eb:jiōng # 駫 0x99ec:ěr # 駬 0x99ed:hài # 駭 0x99ee:bó # 駮 0x99f0:yīn # 駰 0x99f1:luò # 駱 0x99f3:dàn # 駳 0x99f4:hài # 駴 0x99f5:liú # 駵 0x99f6:jú # 駶 0x99f7:sǒng # 駷 0x99f8:qīn # 駸 0x99f9:máng # 駹 0x99fa:liáng,láng # 駺 0x99fb:hàn # 駻 0x99fc:tú # 駼 0x99fd:xuān # 駽 0x99fe:tuì # 駾 0x99ff:jùn # 駿 0x9a00:ě # 騀 0x9a01:chěng # 騁 0x9a02:xīng # 騂 0x9a03:sì # 騃 0x9a04:lù # 騄 0x9a05:zhuī # 騅 0x9a06:zhōu # 騆 0x9a07:shè # 騇 0x9a08:pián # 騈 0x9a09:kūn # 騉 0x9a0a:táo # 騊 0x9a0b:lái # 騋 0x9a0c:zōng # 騌 0x9a0d:kè # 騍 0x9a0e:qí # 騎 0x9a0f:qí # 騏 0x9a10:yàn # 騐 0x9a11:fēi # 騑 0x9a12:sāo # 騒 0x9a13:yàn # 験 0x9a14:gé # 騔 0x9a15:yǎo # 騕 0x9a16:wù # 騖 0x9a17:piàn # 騗 0x9a18:cōng # 騘 0x9a19:piàn # 騙 0x9a1a:qián # 騚 0x9a1b:fēi # 騛 0x9a1c:huáng # 騜 0x9a1d:qián # 騝 0x9a1e:huō # 騞 0x9a1f:yú # 騟 0x9a20:tí # 騠 0x9a21:quán # 騡 0x9a22:xiá # 騢 0x9a23:zōng # 騣 0x9a24:kuí # 騤 0x9a25:róu # 騥 0x9a26:sī # 騦 0x9a27:guā # 騧 0x9a28:tuó # 騨 0x9a29:guī # 騩 0x9a2a:sōu # 騪 0x9a2b:qiān # 騫 0x9a2c:chéng # 騬 0x9a2d:zhì # 騭 0x9a2e:liú # 騮 0x9a2f:péng # 騯 0x9a30:téng # 騰 0x9a31:xí # 騱 0x9a32:cǎo # 騲 0x9a33:dú # 騳 0x9a34:yàn # 騴 0x9a35:yuán # 騵 0x9a36:zōu # 騶 0x9a37:sāo # 騷 0x9a38:shàn # 騸 0x9a39:qí # 騹 0x9a3a:zhì # 騺 0x9a3b:shuāng # 騻 0x9a3c:lù # 騼 0x9a3d:xí # 騽 0x9a3e:luó # 騾 0x9a3f:zhāng # 騿 0x9a40:mò # 驀 0x9a41:ào # 驁 0x9a42:cān # 驂 0x9a43:piào # 驃 0x9a44:cōng # 驄 0x9a45:qū # 驅 0x9a46:bì # 驆 0x9a47:zhì # 驇 0x9a48:yù # 驈 0x9a49:xū # 驉 0x9a4a:huá # 驊 0x9a4b:bō # 驋 0x9a4c:sù # 驌 0x9a4d:xiāo # 驍 0x9a4e:lín # 驎 0x9a4f:zhàn # 驏 0x9a50:dūn # 驐 0x9a51:liú # 驑 0x9a52:tuó # 驒 0x9a53:céng # 驓 0x9a54:diàn # 驔 0x9a55:jiāo # 驕 0x9a56:tiě # 驖 0x9a57:yàn # 驗 0x9a58:luó # 驘 0x9a59:zhān # 驙 0x9a5a:jīng # 驚 0x9a5b:yì # 驛 0x9a5c:yè # 驜 0x9a5d:tuó # 驝 0x9a5e:pīn # 驞 0x9a5f:zhòu # 驟 0x9a60:yàn # 驠 0x9a61:lóng # 驡 0x9a62:lǘ # 驢 0x9a63:téng # 驣 0x9a64:xiāng # 驤 0x9a65:jì # 驥 0x9a66:shuāng # 驦 0x9a67:jú # 驧 0x9a68:xí # 驨 0x9a69:huān # 驩 0x9a6a:lí # 驪 0x9a6b:biāo # 驫 0x9a6c:mǎ # 马 0x9a6d:yù # 驭 0x9a6e:tuó,duò # 驮 0x9a6f:xùn # 驯 0x9a70:chí # 驰 0x9a71:qū # 驱 0x9a72:rì # 驲 0x9a73:bó # 驳 0x9a74:lǘ # 驴 0x9a75:zǎng # 驵 0x9a76:shǐ # 驶 0x9a77:sì # 驷 0x9a78:fù # 驸 0x9a79:jū # 驹 0x9a7a:zōu # 驺 0x9a7b:zhù # 驻 0x9a7c:tuó # 驼 0x9a7d:nú # 驽 0x9a7e:jià # 驾 0x9a7f:yì # 驿 0x9a80:tái # 骀 0x9a81:xiāo # 骁 0x9a82:mà # 骂 0x9a83:yīn # 骃 0x9a84:jiāo # 骄 0x9a85:huá # 骅 0x9a86:luò # 骆 0x9a87:hài # 骇 0x9a88:pián # 骈 0x9a89:biāo # 骉 0x9a8a:lí # 骊 0x9a8b:chěng # 骋 0x9a8c:yàn # 验 0x9a8d:xīng # 骍 0x9a8e:qīn # 骎 0x9a8f:jùn # 骏 0x9a90:qí # 骐 0x9a91:qí # 骑 0x9a92:kè # 骒 0x9a93:zhuī # 骓 0x9a94:zōng # 骔 0x9a95:sù # 骕 0x9a96:cān # 骖 0x9a97:piàn # 骗 0x9a98:zhì # 骘 0x9a99:kuí # 骙 0x9a9a:sāo,sǎo # 骚 0x9a9b:wù # 骛 0x9a9c:áo # 骜 0x9a9d:liú # 骝 0x9a9e:qiān # 骞 0x9a9f:shàn # 骟 0x9aa0:piào,biāo # 骠 0x9aa1:luó # 骡 0x9aa2:cōng # 骢 0x9aa3:chǎn # 骣 0x9aa4:zhòu # 骤 0x9aa5:jì # 骥 0x9aa6:shuāng # 骦 0x9aa7:xiāng # 骧 0x9aa8:gǔ,gū # 骨 0x9aa9:wěi # 骩 0x9aaa:wěi # 骪 0x9aab:wěi # 骫 0x9aac:yú # 骬 0x9aad:gàn # 骭 0x9aae:yì # 骮 0x9aaf:āng # 骯 0x9ab0:tóu # 骰 0x9ab1:jiè # 骱 0x9ab2:bào # 骲 0x9ab3:bèi,mó # 骳 0x9ab4:cī # 骴 0x9ab5:tǐ # 骵 0x9ab6:dǐ # 骶 0x9ab7:kū # 骷 0x9ab8:hái # 骸 0x9ab9:qiāo,xiāo # 骹 0x9aba:hóu # 骺 0x9abb:kuà # 骻 0x9abc:gé # 骼 0x9abd:tuǐ # 骽 0x9abe:gěng # 骾 0x9abf:pián # 骿 0x9ac0:bì # 髀 0x9ac1:kē # 髁 0x9ac2:qià # 髂 0x9ac3:yú # 髃 0x9ac4:suí # 髄 0x9ac5:lóu # 髅 0x9ac6:bó # 髆 0x9ac7:xiāo # 髇 0x9ac8:bǎng,pǎng # 髈 0x9ac9:bó,jué # 髉 0x9aca:cī # 髊 0x9acb:kuān # 髋 0x9acc:bìn # 髌 0x9acd:mó # 髍 0x9ace:liáo # 髎 0x9acf:lóu # 髏 0x9ad0:xiāo # 髐 0x9ad1:dú # 髑 0x9ad2:zāng # 髒 0x9ad3:suǐ # 髓 0x9ad4:tǐ,tī # 體 0x9ad5:bìn # 髕 0x9ad6:kuān # 髖 0x9ad7:lú # 髗 0x9ad8:gāo # 高 0x9ad9:gāo # 髙 0x9ada:qiào # 髚 0x9adb:kāo # 髛 0x9adc:qiǎo # 髜 0x9add:láo # 髝 0x9ade:sào # 髞 0x9adf:biāo # 髟 0x9ae0:kūn # 髠 0x9ae1:kūn # 髡 0x9ae2:dí # 髢 0x9ae3:fǎng # 髣 0x9ae4:xiū # 髤 0x9ae5:rán # 髥 0x9ae6:máo # 髦 0x9ae7:dàn # 髧 0x9ae8:kūn # 髨 0x9ae9:bìn # 髩 0x9aea:fà # 髪 0x9aeb:tiáo # 髫 0x9aec:pī # 髬 0x9aed:zī # 髭 0x9aee:fà # 髮 0x9aef:rán # 髯 0x9af0:tì # 髰 0x9af1:bào # 髱 0x9af2:bì,pǒ # 髲 0x9af3:máo,méng # 髳 0x9af4:fú # 髴 0x9af5:ér # 髵 0x9af6:èr # 髶 0x9af7:qū # 髷 0x9af9:xiū # 髹 0x9afa:kuò,yuè # 髺 0x9afb:jì # 髻 0x9afc:péng # 髼 0x9afd:zhuā # 髽 0x9afe:shāo # 髾 0x9aff:shā # 髿 0x9b00:tì # 鬀 0x9b01:lì # 鬁 0x9b02:bìn # 鬂 0x9b03:zōng # 鬃 0x9b04:tì # 鬄 0x9b05:péng # 鬅 0x9b06:sōng # 鬆 0x9b07:zhēng # 鬇 0x9b08:quán # 鬈 0x9b09:zōng # 鬉 0x9b0a:shùn # 鬊 0x9b0b:jiǎn # 鬋 0x9b0c:duǒ # 鬌 0x9b0d:hú # 鬍 0x9b0e:là # 鬎 0x9b0f:jiū # 鬏 0x9b10:qí # 鬐 0x9b11:lián # 鬑 0x9b12:zhěn # 鬒 0x9b13:bìn # 鬓 0x9b14:péng # 鬔 0x9b15:mà # 鬕 0x9b16:sān # 鬖 0x9b17:mán # 鬗 0x9b18:mán # 鬘 0x9b19:sēng # 鬙 0x9b1a:xū # 鬚 0x9b1b:liè # 鬛 0x9b1c:qiān # 鬜 0x9b1d:qiān # 鬝 0x9b1e:nóng # 鬞 0x9b1f:huán # 鬟 0x9b20:kuò # 鬠 0x9b21:níng # 鬡 0x9b22:bìn # 鬢 0x9b23:liè # 鬣 0x9b24:ráng # 鬤 0x9b25:dòu # 鬥 0x9b26:dòu # 鬦 0x9b27:nào # 鬧 0x9b28:hòng # 鬨 0x9b29:xì # 鬩 0x9b2a:dòu # 鬪 0x9b2b:kàn # 鬫 0x9b2c:dòu # 鬬 0x9b2d:dòu # 鬭 0x9b2e:jiū # 鬮 0x9b2f:chàng # 鬯 0x9b30:yù # 鬰 0x9b31:yù # 鬱 0x9b32:gé,lì # 鬲 0x9b33:yàn # 鬳 0x9b34:fǔ # 鬴 0x9b35:zèng # 鬵 0x9b36:guī # 鬶 0x9b37:zōng # 鬷 0x9b38:liù # 鬸 0x9b39:guī # 鬹 0x9b3a:shāng # 鬺 0x9b3b:yù # 鬻 0x9b3c:guǐ # 鬼 0x9b3d:mèi # 鬽 0x9b3e:jì # 鬾 0x9b3f:qí # 鬿 0x9b40:gà # 魀 0x9b41:kuí # 魁 0x9b42:hún # 魂 0x9b43:bá # 魃 0x9b44:pò,tuò,bó # 魄 0x9b45:mèi # 魅 0x9b46:xū # 魆 0x9b47:yǎn # 魇 0x9b48:xiāo # 魈 0x9b49:liǎng # 魉 0x9b4a:yù # 魊 0x9b4b:tuí # 魋 0x9b4c:qī # 魌 0x9b4d:wǎng # 魍 0x9b4e:liǎng # 魎 0x9b4f:wèi # 魏 0x9b50:gān # 魐 0x9b51:chī # 魑 0x9b52:piāo # 魒 0x9b53:bì # 魓 0x9b54:mó # 魔 0x9b55:jī # 魕 0x9b56:xū # 魖 0x9b57:chǒu # 魗 0x9b58:yǎn # 魘 0x9b59:zhān # 魙 0x9b5a:yú # 魚 0x9b5b:dāo # 魛 0x9b5c:rén # 魜 0x9b5d:jì # 魝 0x9b5f:hóng # 魟 0x9b60:tuō # 魠 0x9b61:diào # 魡 0x9b62:jǐ # 魢 0x9b63:yú # 魣 0x9b64:é # 魤 0x9b65:jì # 魥 0x9b66:shā # 魦 0x9b67:háng # 魧 0x9b68:tún # 魨 0x9b69:mò # 魩 0x9b6a:jiè # 魪 0x9b6b:shěn # 魫 0x9b6c:bǎn # 魬 0x9b6d:yuán # 魭 0x9b6e:pí # 魮 0x9b6f:lǔ # 魯 0x9b70:wén # 魰 0x9b71:hú # 魱 0x9b72:lú # 魲 0x9b73:zā # 魳 0x9b74:fáng # 魴 0x9b75:fén # 魵 0x9b76:nà # 魶 0x9b77:yóu # 魷 0x9b7a:hé # 魺 0x9b7b:xiá # 魻 0x9b7c:qū # 魼 0x9b7d:hān # 魽 0x9b7e:pī # 魾 0x9b7f:líng # 魿 0x9b80:tuó # 鮀 0x9b81:bà # 鮁 0x9b82:qiú # 鮂 0x9b83:píng # 鮃 0x9b84:fú # 鮄 0x9b85:bì # 鮅 0x9b86:cǐ,jì # 鮆 0x9b87:wèi # 鮇 0x9b88:jū # 鮈 0x9b89:diāo # 鮉 0x9b8a:bó,bà # 鮊 0x9b8b:yóu # 鮋 0x9b8c:gǔn # 鮌 0x9b8d:pí # 鮍 0x9b8e:nián # 鮎 0x9b8f:xīng # 鮏 0x9b90:tái # 鮐 0x9b91:bào # 鮑 0x9b92:fù # 鮒 0x9b93:zhǎ,zhà # 鮓 0x9b94:jù # 鮔 0x9b95:gū # 鮕 0x9b99:tǎ # 鮙 0x9b9a:jié # 鮚 0x9b9b:shū # 鮛 0x9b9c:hòu # 鮜 0x9b9d:xiǎng # 鮝 0x9b9e:ér # 鮞 0x9b9f:ān # 鮟 0x9ba0:wéi # 鮠 0x9ba1:zhào # 鮡 0x9ba2:zhū # 鮢 0x9ba3:yìn # 鮣 0x9ba4:liè # 鮤 0x9ba5:luò,gé # 鮥 0x9ba6:tóng # 鮦 0x9ba7:yí # 鮧 0x9ba8:yì # 鮨 0x9ba9:bìng # 鮩 0x9baa:wěi # 鮪 0x9bab:jiāo # 鮫 0x9bac:kū # 鮬 0x9bad:guī,xié,wā,kuí # 鮭 0x9bae:xiān,xiǎn # 鮮 0x9baf:gé # 鮯 0x9bb0:huí # 鮰 0x9bb3:kào # 鮳 0x9bb5:tuō # 鮵 0x9bb6:jūn # 鮶 0x9bb7:tí # 鮷 0x9bb8:miǎn # 鮸 0x9bb9:shāo # 鮹 0x9bba:zhǎ # 鮺 0x9bbb:suō # 鮻 0x9bbc:qīn # 鮼 0x9bbd:yú # 鮽 0x9bbe:něi # 鮾 0x9bbf:zhé # 鮿 0x9bc0:gǔn # 鯀 0x9bc1:gěng # 鯁 0x9bc3:wú # 鯃 0x9bc4:qiú # 鯄 0x9bc5:shān # 鯅 0x9bc6:pū,bū # 鯆 0x9bc7:huàn # 鯇 0x9bc8:tiáo # 鯈 0x9bc9:lǐ # 鯉 0x9bca:shā # 鯊 0x9bcb:shā # 鯋 0x9bcc:kào # 鯌 0x9bcd:méng # 鯍 0x9bd2:yǒng # 鯒 0x9bd3:shēn # 鯓 0x9bd4:zī # 鯔 0x9bd5:qí # 鯕 0x9bd6:qīng,zhēng # 鯖 0x9bd7:xiǎng # 鯗 0x9bd8:něi # 鯘 0x9bd9:chún # 鯙 0x9bda:jì # 鯚 0x9bdb:diāo # 鯛 0x9bdc:qiè # 鯜 0x9bdd:gù # 鯝 0x9bde:zhǒu # 鯞 0x9bdf:dōng # 鯟 0x9be0:lái # 鯠 0x9be1:fēi # 鯡 0x9be2:ní # 鯢 0x9be3:yì,sī # 鯣 0x9be4:kūn # 鯤 0x9be5:lù # 鯥 0x9be6:jiù # 鯦 0x9be7:chāng # 鯧 0x9be8:jīng # 鯨 0x9be9:lún # 鯩 0x9bea:líng # 鯪 0x9beb:zōu # 鯫 0x9bec:lí # 鯬 0x9bed:měng # 鯭 0x9bee:zōng # 鯮 0x9bef:zhì # 鯯 0x9bf0:nián # 鯰 0x9bf4:shī # 鯴 0x9bf5:shēn # 鯵 0x9bf6:huàn # 鯶 0x9bf7:tí # 鯷 0x9bf8:hóu # 鯸 0x9bf9:xīng # 鯹 0x9bfa:zhū # 鯺 0x9bfb:là # 鯻 0x9bfc:zōng # 鯼 0x9bfd:jì # 鯽 0x9bfe:biān # 鯾 0x9bff:biān # 鯿 0x9c00:huàn # 鰀 0x9c01:quán # 鰁 0x9c02:zéi # 鰂 0x9c03:wēi # 鰃 0x9c04:wēi # 鰄 0x9c05:yú # 鰅 0x9c06:chūn # 鰆 0x9c07:róu # 鰇 0x9c08:dié # 鰈 0x9c09:huáng # 鰉 0x9c0a:liàn # 鰊 0x9c0b:yǎn # 鰋 0x9c0c:qiū # 鰌 0x9c0d:qiū # 鰍 0x9c0e:jiǎn # 鰎 0x9c0f:bī # 鰏 0x9c10:è # 鰐 0x9c11:yáng # 鰑 0x9c12:fù # 鰒 0x9c13:sāi,xǐ # 鰓 0x9c14:jiān # 鰔 0x9c15:xiā # 鰕 0x9c16:tuǒ # 鰖 0x9c17:hú # 鰗 0x9c19:ruò # 鰙 0x9c1b:wēn # 鰛 0x9c1c:jiān # 鰜 0x9c1d:hào # 鰝 0x9c1e:wū # 鰞 0x9c1f:páng # 鰟 0x9c20:sāo # 鰠 0x9c21:liú # 鰡 0x9c22:mǎ # 鰢 0x9c23:shí # 鰣 0x9c24:shī # 鰤 0x9c25:guān # 鰥 0x9c27:téng # 鰧 0x9c28:tǎ # 鰨 0x9c29:yáo # 鰩 0x9c2a:è # 鰪 0x9c2b:yóng # 鰫 0x9c2c:qián # 鰬 0x9c2d:qí # 鰭 0x9c2e:wēn # 鰮 0x9c2f:ruò # 鰯 0x9c31:lián # 鰱 0x9c32:áo # 鰲 0x9c33:lè # 鰳 0x9c34:huī # 鰴 0x9c35:mǐn # 鰵 0x9c36:jì # 鰶 0x9c37:tiáo # 鰷 0x9c38:qū # 鰸 0x9c39:jiān # 鰹 0x9c3a:shēn # 鰺 0x9c3b:mán # 鰻 0x9c3c:xí # 鰼 0x9c3d:qiú # 鰽 0x9c3e:piào # 鰾 0x9c3f:jì # 鰿 0x9c40:jì # 鱀 0x9c41:zhú # 鱁 0x9c42:jiāng # 鱂 0x9c43:xiū # 鱃 0x9c44:zhuān # 鱄 0x9c45:yōng # 鱅 0x9c46:zhāng # 鱆 0x9c47:kāng # 鱇 0x9c48:xuě # 鱈 0x9c49:biē # 鱉 0x9c4a:yù # 鱊 0x9c4b:qū # 鱋 0x9c4c:xiàng # 鱌 0x9c4d:bō # 鱍 0x9c4e:jiǎo # 鱎 0x9c4f:xún # 鱏 0x9c50:sù # 鱐 0x9c51:huáng # 鱑 0x9c52:zūn # 鱒 0x9c53:shàn # 鱓 0x9c54:shàn # 鱔 0x9c55:fān # 鱕 0x9c56:guì # 鱖 0x9c57:lín # 鱗 0x9c58:xún # 鱘 0x9c59:yáo # 鱙 0x9c5a:xǐ # 鱚 0x9c5d:fèn # 鱝 0x9c5e:guān # 鱞 0x9c5f:hòu # 鱟 0x9c60:kuài # 鱠 0x9c61:zéi # 鱡 0x9c62:sāo # 鱢 0x9c63:zhān # 鱣 0x9c64:gǎn # 鱤 0x9c65:guì # 鱥 0x9c66:yìng # 鱦 0x9c67:lǐ # 鱧 0x9c68:cháng # 鱨 0x9c6c:rú # 鱬 0x9c6d:jì # 鱭 0x9c6e:xù # 鱮 0x9c6f:hù # 鱯 0x9c71:lǐ # 鱱 0x9c72:liè # 鱲 0x9c73:lè # 鱳 0x9c74:miè # 鱴 0x9c75:zhēn # 鱵 0x9c76:xiǎng # 鱶 0x9c77:è # 鱷 0x9c78:lú # 鱸 0x9c79:guàn # 鱹 0x9c7a:lí # 鱺 0x9c7b:xiān # 鱻 0x9c7c:yú # 鱼 0x9c7d:dāo # 鱽 0x9c7e:jǐ # 鱾 0x9c7f:yóu # 鱿 0x9c80:tún # 鲀 0x9c81:lǔ # 鲁 0x9c82:fáng # 鲂 0x9c83:bā,bà # 鲃 0x9c84:hé,gě # 鲄 0x9c85:bà # 鲅 0x9c86:píng # 鲆 0x9c87:nián # 鲇 0x9c88:lú # 鲈 0x9c89:yóu # 鲉 0x9c8a:zhǎ,zhà # 鲊 0x9c8b:fù # 鲋 0x9c8c:bó,bà # 鲌 0x9c8d:bào # 鲍 0x9c8e:hòu # 鲎 0x9c8f:pí # 鲏 0x9c90:tái # 鲐 0x9c91:guī,xié # 鲑 0x9c92:jié # 鲒 0x9c93:kào # 鲓 0x9c94:wěi # 鲔 0x9c95:ér # 鲕 0x9c96:tóng # 鲖 0x9c97:zéi # 鲗 0x9c98:hòu # 鲘 0x9c99:kuài # 鲙 0x9c9a:jì # 鲚 0x9c9b:jiāo # 鲛 0x9c9c:xiān,xiǎn # 鲜 0x9c9d:zhǎ # 鲝 0x9c9e:xiǎng # 鲞 0x9c9f:xún # 鲟 0x9ca0:gěng # 鲠 0x9ca1:lí # 鲡 0x9ca2:lián # 鲢 0x9ca3:jiān # 鲣 0x9ca4:lǐ # 鲤 0x9ca5:shí # 鲥 0x9ca6:tiáo # 鲦 0x9ca7:gǔn # 鲧 0x9ca8:shā # 鲨 0x9ca9:huàn # 鲩 0x9caa:jūn # 鲪 0x9cab:jì # 鲫 0x9cac:yǒng # 鲬 0x9cad:qīng,zhēng # 鲭 0x9cae:líng # 鲮 0x9caf:qí # 鲯 0x9cb0:zōu # 鲰 0x9cb1:fēi # 鲱 0x9cb2:kūn # 鲲 0x9cb3:chāng # 鲳 0x9cb4:gù # 鲴 0x9cb5:ní # 鲵 0x9cb6:nián # 鲶 0x9cb7:diāo # 鲷 0x9cb8:jīng # 鲸 0x9cb9:shēn # 鲹 0x9cba:shī # 鲺 0x9cbb:zī # 鲻 0x9cbc:fèn # 鲼 0x9cbd:dié # 鲽 0x9cbe:bī # 鲾 0x9cbf:cháng # 鲿 0x9cc0:tí # 鳀 0x9cc1:wēn # 鳁 0x9cc2:wēi # 鳂 0x9cc3:sāi,xǐ # 鳃 0x9cc4:è # 鳄 0x9cc5:qiū # 鳅 0x9cc6:fù # 鳆 0x9cc7:huáng # 鳇 0x9cc8:quán # 鳈 0x9cc9:jiāng # 鳉 0x9cca:biān # 鳊 0x9ccb:sāo # 鳋 0x9ccc:áo # 鳌 0x9ccd:qí # 鳍 0x9cce:tǎ # 鳎 0x9ccf:guān # 鳏 0x9cd0:yáo # 鳐 0x9cd1:páng # 鳑 0x9cd2:jiān # 鳒 0x9cd3:lè # 鳓 0x9cd4:biào # 鳔 0x9cd5:xuě # 鳕 0x9cd6:biē # 鳖 0x9cd7:mán # 鳗 0x9cd8:mǐn # 鳘 0x9cd9:yōng # 鳙 0x9cda:wèi # 鳚 0x9cdb:xí # 鳛 0x9cdc:guì,jué # 鳜 0x9cdd:shàn # 鳝 0x9cde:lín # 鳞 0x9cdf:zūn # 鳟 0x9ce0:hù # 鳠 0x9ce1:gǎn # 鳡 0x9ce2:lǐ # 鳢 0x9ce3:zhān,shàn # 鳣 0x9ce4:guǎn # 鳤 0x9ce5:niǎo,diǎo # 鳥 0x9ce6:yǐ # 鳦 0x9ce7:fú # 鳧 0x9ce8:lì # 鳨 0x9ce9:jiū # 鳩 0x9cea:bú # 鳪 0x9ceb:yàn # 鳫 0x9cec:fú # 鳬 0x9ced:diāo,zhāo # 鳭 0x9cee:jī # 鳮 0x9cef:fèng # 鳯 0x9cf1:gān,hàn,yàn # 鳱 0x9cf2:shī # 鳲 0x9cf3:fèng # 鳳 0x9cf4:míng # 鳴 0x9cf5:bǎo # 鳵 0x9cf6:yuān # 鳶 0x9cf7:zhī # 鳷 0x9cf8:hù # 鳸 0x9cf9:qín # 鳹 0x9cfa:fū,guī # 鳺 0x9cfb:bān,fén # 鳻 0x9cfc:wén # 鳼 0x9cfd:jiān,qiān,zhān # 鳽 0x9cfe:shī # 鳾 0x9cff:yù # 鳿 0x9d00:fǒu # 鴀 0x9d01:yāo # 鴁 0x9d02:jué # 鴂 0x9d03:jué # 鴃 0x9d04:pǐ # 鴄 0x9d05:huān # 鴅 0x9d06:zhèn # 鴆 0x9d07:bǎo # 鴇 0x9d08:yàn # 鴈 0x9d09:yā # 鴉 0x9d0a:zhèng # 鴊 0x9d0b:fāng # 鴋 0x9d0c:fèng # 鴌 0x9d0d:wén # 鴍 0x9d0e:ōu # 鴎 0x9d0f:dài # 鴏 0x9d10:jiā # 鴐 0x9d11:rú # 鴑 0x9d12:líng # 鴒 0x9d13:miè # 鴓 0x9d14:fú # 鴔 0x9d15:tuó # 鴕 0x9d16:mín # 鴖 0x9d17:lì # 鴗 0x9d18:biǎn # 鴘 0x9d19:zhì # 鴙 0x9d1a:gē # 鴚 0x9d1b:yuān # 鴛 0x9d1c:cí # 鴜 0x9d1d:qú # 鴝 0x9d1e:xiāo # 鴞 0x9d1f:chī # 鴟 0x9d20:dàn # 鴠 0x9d21:jū # 鴡 0x9d22:yāo # 鴢 0x9d23:gū # 鴣 0x9d24:zhōng # 鴤 0x9d25:yù # 鴥 0x9d26:yāng # 鴦 0x9d27:yù # 鴧 0x9d28:yā # 鴨 0x9d29:dié # 鴩 0x9d2a:yù # 鴪 0x9d2c:yīng # 鴬 0x9d2d:duī # 鴭 0x9d2e:wū # 鴮 0x9d2f:ér # 鴯 0x9d30:guā # 鴰 0x9d31:ài # 鴱 0x9d32:zhī # 鴲 0x9d33:yàn # 鴳 0x9d34:héng # 鴴 0x9d35:xiāo # 鴵 0x9d36:jiá # 鴶 0x9d37:liè # 鴷 0x9d38:zhū # 鴸 0x9d39:yáng # 鴹 0x9d3a:yí # 鴺 0x9d3b:hóng # 鴻 0x9d3c:lù # 鴼 0x9d3d:rú # 鴽 0x9d3e:móu # 鴾 0x9d3f:gē # 鴿 0x9d40:rén # 鵀 0x9d41:jiāo # 鵁 0x9d42:xiū # 鵂 0x9d43:zhōu # 鵃 0x9d44:chī # 鵄 0x9d45:luò # 鵅 0x9d49:luán # 鵉 0x9d4a:jiá # 鵊 0x9d4b:jì # 鵋 0x9d4c:tú # 鵌 0x9d4d:huān # 鵍 0x9d4e:tuǒ # 鵎 0x9d4f:bū # 鵏 0x9d50:wú # 鵐 0x9d51:jiān # 鵑 0x9d52:yù # 鵒 0x9d53:bó # 鵓 0x9d54:jùn # 鵔 0x9d55:jùn # 鵕 0x9d56:bī # 鵖 0x9d57:xī # 鵗 0x9d58:jùn # 鵘 0x9d59:jú # 鵙 0x9d5a:tū # 鵚 0x9d5b:jìng # 鵛 0x9d5c:tí # 鵜 0x9d5d:é # 鵝 0x9d5e:é # 鵞 0x9d5f:kuáng # 鵟 0x9d60:hú # 鵠 0x9d61:wǔ # 鵡 0x9d62:shēn # 鵢 0x9d63:lài # 鵣 0x9d66:lù # 鵦 0x9d67:pí # 鵧 0x9d68:shū # 鵨 0x9d69:fú # 鵩 0x9d6a:ān # 鵪 0x9d6b:zhuó # 鵫 0x9d6c:péng # 鵬 0x9d6d:qín # 鵭 0x9d6e:qiān # 鵮 0x9d6f:bēi # 鵯 0x9d70:diāo # 鵰 0x9d71:lù # 鵱 0x9d72:què # 鵲 0x9d73:jiān # 鵳 0x9d74:jú # 鵴 0x9d75:tù # 鵵 0x9d76:yā # 鵶 0x9d77:yuān # 鵷 0x9d78:qí # 鵸 0x9d79:lí # 鵹 0x9d7a:yè # 鵺 0x9d7b:zhuī # 鵻 0x9d7c:kōng # 鵼 0x9d7d:duò # 鵽 0x9d7e:kūn # 鵾 0x9d7f:shēng # 鵿 0x9d80:qí # 鶀 0x9d81:jīng # 鶁 0x9d82:yì # 鶂 0x9d83:yì # 鶃 0x9d84:jīng # 鶄 0x9d85:zī # 鶅 0x9d86:lái # 鶆 0x9d87:dōng # 鶇 0x9d88:qī # 鶈 0x9d89:chún # 鶉 0x9d8a:gēng # 鶊 0x9d8b:jū # 鶋 0x9d8c:qū # 鶌 0x9d8f:jī # 鶏 0x9d90:shù # 鶐 0x9d92:chì # 鶒 0x9d93:miáo # 鶓 0x9d94:róu # 鶔 0x9d95:ān # 鶕 0x9d96:qiū # 鶖 0x9d97:tí,chí # 鶗 0x9d98:hú # 鶘 0x9d99:tí,chí # 鶙 0x9d9a:è # 鶚 0x9d9b:jiē # 鶛 0x9d9c:máo # 鶜 0x9d9d:fú,bì # 鶝 0x9d9e:chūn # 鶞 0x9d9f:tú # 鶟 0x9da0:yǎn # 鶠 0x9da1:hé,jiè # 鶡 0x9da2:yuán # 鶢 0x9da3:piān,biǎn # 鶣 0x9da4:kūn # 鶤 0x9da5:méi # 鶥 0x9da6:hú # 鶦 0x9da7:yīng # 鶧 0x9da8:chuàn,zhì # 鶨 0x9da9:wù # 鶩 0x9daa:jú # 鶪 0x9dac:cāng,qiāng # 鶬 0x9dad:fǎng # 鶭 0x9dae:hè,hú # 鶮 0x9daf:yīng # 鶯 0x9db0:yuán # 鶰 0x9db1:xiān # 鶱 0x9db2:wēng # 鶲 0x9db3:shī # 鶳 0x9db4:hè # 鶴 0x9db5:chú # 鶵 0x9db6:táng # 鶶 0x9db7:xiá # 鶷 0x9db8:ruò # 鶸 0x9db9:liú # 鶹 0x9dba:jī # 鶺 0x9dbb:gǔ,hú # 鶻 0x9dbc:jiān # 鶼 0x9dbd:sǔn,xùn # 鶽 0x9dbe:hàn # 鶾 0x9dbf:cí # 鶿 0x9dc0:cí # 鷀 0x9dc1:yì # 鷁 0x9dc2:yào # 鷂 0x9dc3:yàn # 鷃 0x9dc4:jī # 鷄 0x9dc5:lì # 鷅 0x9dc6:tián # 鷆 0x9dc7:kòu # 鷇 0x9dc8:tī # 鷈 0x9dc9:tī # 鷉 0x9dca:yì # 鷊 0x9dcb:tú # 鷋 0x9dcc:mǎ # 鷌 0x9dcd:xiāo # 鷍 0x9dce:gāo # 鷎 0x9dcf:tián # 鷏 0x9dd0:chén # 鷐 0x9dd1:jì # 鷑 0x9dd2:tuán # 鷒 0x9dd3:zhè # 鷓 0x9dd4:áo # 鷔 0x9dd5:yǎo # 鷕 0x9dd6:yī # 鷖 0x9dd7:ōu # 鷗 0x9dd8:chì # 鷘 0x9dd9:zhì # 鷙 0x9dda:liù # 鷚 0x9ddb:yōng # 鷛 0x9ddc:lóu,lǚ # 鷜 0x9ddd:bì # 鷝 0x9dde:shuāng # 鷞 0x9ddf:zhuó # 鷟 0x9de0:yú # 鷠 0x9de1:wú # 鷡 0x9de2:jué # 鷢 0x9de3:yín # 鷣 0x9de4:tí # 鷤 0x9de5:sī # 鷥 0x9de6:jiāo # 鷦 0x9de7:yì # 鷧 0x9de8:huá # 鷨 0x9de9:bì # 鷩 0x9dea:yīng # 鷪 0x9deb:sù # 鷫 0x9dec:huáng # 鷬 0x9ded:fán # 鷭 0x9dee:jiāo # 鷮 0x9def:liáo # 鷯 0x9df0:yàn # 鷰 0x9df1:gāo # 鷱 0x9df2:jiù # 鷲 0x9df3:xián # 鷳 0x9df4:xián # 鷴 0x9df5:tú # 鷵 0x9df6:mǎi # 鷶 0x9df7:zūn # 鷷 0x9df8:yù # 鷸 0x9df9:yīng # 鷹 0x9dfa:lù # 鷺 0x9dfb:tuán # 鷻 0x9dfc:xián # 鷼 0x9dfd:xué # 鷽 0x9dfe:yì # 鷾 0x9dff:pì # 鷿 0x9e00:zhǔ # 鸀 0x9e01:luó # 鸁 0x9e02:xī # 鸂 0x9e03:yì # 鸃 0x9e04:jī # 鸄 0x9e05:zé # 鸅 0x9e06:yú # 鸆 0x9e07:zhān # 鸇 0x9e08:yè # 鸈 0x9e09:yáng # 鸉 0x9e0a:pì # 鸊 0x9e0b:níng # 鸋 0x9e0c:hù # 鸌 0x9e0d:mí # 鸍 0x9e0e:yīng # 鸎 0x9e0f:méng # 鸏 0x9e10:dí # 鸐 0x9e11:yuè # 鸑 0x9e12:yù # 鸒 0x9e13:lěi # 鸓 0x9e14:bǔ # 鸔 0x9e15:lú # 鸕 0x9e16:hè # 鸖 0x9e17:lóng # 鸗 0x9e18:shuāng # 鸘 0x9e19:yuè # 鸙 0x9e1a:yīng # 鸚 0x9e1b:guàn # 鸛 0x9e1c:qú # 鸜 0x9e1d:lí # 鸝 0x9e1e:luán # 鸞 0x9e1f:niǎo,diǎo # 鸟 0x9e20:jiū # 鸠 0x9e21:jī # 鸡 0x9e22:yuān # 鸢 0x9e23:míng # 鸣 0x9e24:shī # 鸤 0x9e25:ōu # 鸥 0x9e26:yā # 鸦 0x9e27:cāng # 鸧 0x9e28:bǎo # 鸨 0x9e29:zhèn # 鸩 0x9e2a:gū # 鸪 0x9e2b:dōng # 鸫 0x9e2c:lú # 鸬 0x9e2d:yā # 鸭 0x9e2e:xiāo # 鸮 0x9e2f:yāng # 鸯 0x9e30:líng # 鸰 0x9e31:chī # 鸱 0x9e32:qú # 鸲 0x9e33:yuān # 鸳 0x9e34:xué # 鸴 0x9e35:tuó # 鸵 0x9e36:sī # 鸶 0x9e37:zhì # 鸷 0x9e38:ér # 鸸 0x9e39:guā # 鸹 0x9e3a:xiū # 鸺 0x9e3b:héng # 鸻 0x9e3c:zhōu # 鸼 0x9e3d:gē # 鸽 0x9e3e:luán # 鸾 0x9e3f:hóng # 鸿 0x9e40:wú # 鹀 0x9e41:bó # 鹁 0x9e42:lí # 鹂 0x9e43:juān # 鹃 0x9e44:hú,gǔ,hè # 鹄 0x9e45:é # 鹅 0x9e46:yù # 鹆 0x9e47:xián # 鹇 0x9e48:tí # 鹈 0x9e49:wǔ # 鹉 0x9e4a:què # 鹊 0x9e4b:miáo # 鹋 0x9e4c:ān # 鹌 0x9e4d:kūn # 鹍 0x9e4e:bēi # 鹎 0x9e4f:péng # 鹏 0x9e50:qiān # 鹐 0x9e51:chún # 鹑 0x9e52:gēng # 鹒 0x9e53:yuān # 鹓 0x9e54:sù # 鹔 0x9e55:hú # 鹕 0x9e56:hé # 鹖 0x9e57:è # 鹗 0x9e58:gǔ,hú # 鹘 0x9e59:qiū # 鹙 0x9e5a:cí # 鹚 0x9e5b:méi # 鹛 0x9e5c:wù # 鹜 0x9e5d:yì # 鹝 0x9e5e:yào # 鹞 0x9e5f:wēng # 鹟 0x9e60:liú # 鹠 0x9e61:jī # 鹡 0x9e62:yì # 鹢 0x9e63:jiān # 鹣 0x9e64:hè # 鹤 0x9e65:yī # 鹥 0x9e66:yīng # 鹦 0x9e67:zhè # 鹧 0x9e68:liù # 鹨 0x9e69:liáo # 鹩 0x9e6a:jiāo # 鹪 0x9e6b:jiù # 鹫 0x9e6c:yù # 鹬 0x9e6d:lù # 鹭 0x9e6e:huán # 鹮 0x9e6f:zhān # 鹯 0x9e70:yīng # 鹰 0x9e71:hù # 鹱 0x9e72:méng # 鹲 0x9e73:guàn # 鹳 0x9e74:shuāng # 鹴 0x9e75:lǔ # 鹵 0x9e76:jīn # 鹶 0x9e77:líng # 鹷 0x9e78:jiǎn # 鹸 0x9e79:xián # 鹹 0x9e7a:cuó # 鹺 0x9e7b:jiǎn # 鹻 0x9e7c:jiǎn # 鹼 0x9e7d:yán # 鹽 0x9e7e:cuó # 鹾 0x9e7f:lù # 鹿 0x9e80:yōu # 麀 0x9e81:cū # 麁 0x9e82:jǐ # 麂 0x9e83:páo,biāo # 麃 0x9e84:cū # 麄 0x9e85:páo # 麅 0x9e86:zhù,cū # 麆 0x9e87:jūn,qún # 麇 0x9e88:zhǔ # 麈 0x9e89:jiān # 麉 0x9e8a:mí # 麊 0x9e8b:mí # 麋 0x9e8c:yǔ # 麌 0x9e8d:liú # 麍 0x9e8e:chén # 麎 0x9e8f:jūn # 麏 0x9e90:lín # 麐 0x9e91:ní # 麑 0x9e92:qí # 麒 0x9e93:lù # 麓 0x9e94:jiù # 麔 0x9e95:jūn # 麕 0x9e96:jīng # 麖 0x9e97:lí,lì # 麗 0x9e98:xiāng # 麘 0x9e99:xián # 麙 0x9e9a:jiā # 麚 0x9e9b:mí # 麛 0x9e9c:lì # 麜 0x9e9d:shè # 麝 0x9e9e:zhāng # 麞 0x9e9f:lín # 麟 0x9ea0:jīng # 麠 0x9ea1:qí # 麡 0x9ea2:líng # 麢 0x9ea3:yán # 麣 0x9ea4:cū # 麤 0x9ea5:mài # 麥 0x9ea6:mài # 麦 0x9ea7:hé # 麧 0x9ea8:chǎo # 麨 0x9ea9:fū # 麩 0x9eaa:miàn # 麪 0x9eab:miàn # 麫 0x9eac:fū # 麬 0x9ead:pào # 麭 0x9eae:qù # 麮 0x9eaf:qū # 麯 0x9eb0:móu # 麰 0x9eb1:fū # 麱 0x9eb2:xiàn # 麲 0x9eb3:lái # 麳 0x9eb4:qū # 麴 0x9eb5:miàn # 麵 0x9eb7:fēng # 麷 0x9eb8:fū # 麸 0x9eb9:qū # 麹 0x9eba:miàn # 麺 0x9ebb:má # 麻 0x9ebc:mó,me # 麼 0x9ebd:mó,me,ma # 麽 0x9ebe:huī # 麾 0x9ec0:zōu # 黀 0x9ec1:nún # 黁 0x9ec2:fén # 黂 0x9ec3:huáng # 黃 0x9ec4:huáng # 黄 0x9ec5:jīn # 黅 0x9ec6:guāng # 黆 0x9ec7:tiān # 黇 0x9ec8:tǒu # 黈 0x9ec9:hóng # 黉 0x9eca:huà # 黊 0x9ecb:kuàng # 黋 0x9ecc:hóng # 黌 0x9ecd:shǔ # 黍 0x9ece:lí # 黎 0x9ecf:nián # 黏 0x9ed0:chī # 黐 0x9ed1:hēi # 黑 0x9ed2:hēi # 黒 0x9ed3:yì # 黓 0x9ed4:qián # 黔 0x9ed5:dǎn # 黕 0x9ed6:xì # 黖 0x9ed7:tún # 黗 0x9ed8:mò # 默 0x9ed9:mò # 黙 0x9eda:qián # 黚 0x9edb:dài # 黛 0x9edc:chù # 黜 0x9edd:yǒu # 黝 0x9ede:diǎn # 點 0x9edf:yī # 黟 0x9ee0:xiá # 黠 0x9ee1:yǎn # 黡 0x9ee2:qū # 黢 0x9ee3:měi # 黣 0x9ee4:yǎn # 黤 0x9ee5:qíng # 黥 0x9ee6:yuè # 黦 0x9ee7:lí # 黧 0x9ee8:dǎng # 黨 0x9ee9:dú # 黩 0x9eea:cǎn # 黪 0x9eeb:yān # 黫 0x9eec:yǎn # 黬 0x9eed:yǎn # 黭 0x9eee:dàn,shèn # 黮 0x9eef:àn # 黯 0x9ef0:zhěn,yān # 黰 0x9ef1:dài # 黱 0x9ef2:cǎn # 黲 0x9ef3:yī # 黳 0x9ef4:méi # 黴 0x9ef5:dǎn,zhǎn # 黵 0x9ef6:yǎn # 黶 0x9ef7:dú # 黷 0x9ef8:lú # 黸 0x9ef9:zhǐ # 黹 0x9efa:fěn # 黺 0x9efb:fú # 黻 0x9efc:fǔ # 黼 0x9efd:mǐn,miǎn,měng # 黽 0x9efe:mǐn,miǎn,měng # 黾 0x9eff:yuán # 黿 0x9f00:cù # 鼀 0x9f01:qù # 鼁 0x9f02:cháo # 鼂 0x9f03:wā # 鼃 0x9f04:zhū # 鼄 0x9f05:zhī # 鼅 0x9f06:měng # 鼆 0x9f07:áo # 鼇 0x9f08:biē # 鼈 0x9f09:tuó # 鼉 0x9f0a:bì # 鼊 0x9f0b:yuán # 鼋 0x9f0c:cháo,zhāo # 鼌 0x9f0d:tuó # 鼍 0x9f0e:dǐng # 鼎 0x9f0f:mì # 鼏 0x9f10:nài # 鼐 0x9f11:dǐng # 鼑 0x9f12:zī # 鼒 0x9f13:gǔ # 鼓 0x9f14:gǔ # 鼔 0x9f15:dōng # 鼕 0x9f16:fén # 鼖 0x9f17:táo # 鼗 0x9f18:yuān # 鼘 0x9f19:pí # 鼙 0x9f1a:chāng # 鼚 0x9f1b:gāo # 鼛 0x9f1c:cào # 鼜 0x9f1d:yuān # 鼝 0x9f1e:tāng # 鼞 0x9f1f:tēng # 鼟 0x9f20:shǔ # 鼠 0x9f21:shǔ # 鼡 0x9f22:fén # 鼢 0x9f23:fèi # 鼣 0x9f24:wén # 鼤 0x9f25:bá # 鼥 0x9f26:diāo # 鼦 0x9f27:tuó # 鼧 0x9f28:zhōng # 鼨 0x9f29:qú # 鼩 0x9f2a:shēng # 鼪 0x9f2b:shí # 鼫 0x9f2c:yòu # 鼬 0x9f2d:shí # 鼭 0x9f2e:tíng # 鼮 0x9f2f:wú # 鼯 0x9f30:jú # 鼰 0x9f31:jīng # 鼱 0x9f32:hún # 鼲 0x9f33:jú # 鼳 0x9f34:yǎn # 鼴 0x9f35:tū # 鼵 0x9f36:sī # 鼶 0x9f37:xī # 鼷 0x9f38:xiàn # 鼸 0x9f39:yǎn # 鼹 0x9f3a:léi # 鼺 0x9f3b:bí # 鼻 0x9f3c:yào # 鼼 0x9f3d:qiú # 鼽 0x9f3e:hān # 鼾 0x9f3f:wù # 鼿 0x9f40:wù # 齀 0x9f41:hōu # 齁 0x9f42:xiè # 齂 0x9f43:è # 齃 0x9f44:zhā # 齄 0x9f45:xiù # 齅 0x9f46:wèng # 齆 0x9f47:zhā # 齇 0x9f48:nòng # 齈 0x9f49:nàng # 齉 0x9f4a:qí,zhāi # 齊 0x9f4b:zhāi # 齋 0x9f4c:jì # 齌 0x9f4d:zī # 齍 0x9f4e:jí # 齎 0x9f4f:jī # 齏 0x9f50:qí,jì,zī,zhāi # 齐 0x9f51:jī # 齑 0x9f52:chǐ # 齒 0x9f53:chèn # 齓 0x9f54:chèn # 齔 0x9f55:hé # 齕 0x9f56:yá # 齖 0x9f57:yīn # 齗 0x9f58:xiè # 齘 0x9f59:bāo # 齙 0x9f5a:zé # 齚 0x9f5b:xiè # 齛 0x9f5c:zī # 齜 0x9f5d:chī # 齝 0x9f5e:yàn # 齞 0x9f5f:jǔ # 齟 0x9f60:tiáo # 齠 0x9f61:líng # 齡 0x9f62:líng # 齢 0x9f63:chū # 齣 0x9f64:quán # 齤 0x9f65:xiè # 齥 0x9f66:yín # 齦 0x9f67:niè # 齧 0x9f68:jiù # 齨 0x9f69:yǎo # 齩 0x9f6a:chuò # 齪 0x9f6b:yǔn # 齫 0x9f6c:yǔ # 齬 0x9f6d:chǔ # 齭 0x9f6e:yǐ # 齮 0x9f6f:ní # 齯 0x9f70:zé # 齰 0x9f71:zōu # 齱 0x9f72:qǔ # 齲 0x9f73:yǔn # 齳 0x9f74:yǎn # 齴 0x9f75:yú # 齵 0x9f76:è # 齶 0x9f77:wò # 齷 0x9f78:yì # 齸 0x9f79:cī # 齹 0x9f7a:zōu # 齺 0x9f7b:diān # 齻 0x9f7c:chǔ # 齼 0x9f7d:jìn # 齽 0x9f7e:yà # 齾 0x9f7f:chǐ # 齿 0x9f80:chèn # 龀 0x9f81:hé # 龁 0x9f82:yín,kěn # 龂 0x9f83:jǔ # 龃 0x9f84:líng # 龄 0x9f85:bāo # 龅 0x9f86:tiáo # 龆 0x9f87:zī # 龇 0x9f88:yín,kěn # 龈 0x9f89:yǔ # 龉 0x9f8a:chuò # 龊 0x9f8b:qǔ # 龋 0x9f8c:wò # 龌 0x9f8d:lóng,lǒng # 龍 0x9f8e:páng # 龎 0x9f8f:gōng,wò # 龏 0x9f90:páng # 龐 0x9f91:yǎn # 龑 0x9f92:lóng # 龒 0x9f93:lóng,lǒng # 龓 0x9f94:gōng # 龔 0x9f95:kān # 龕 0x9f96:dá # 龖 0x9f97:líng # 龗 0x9f98:dá # 龘 0x9f99:lóng # 龙 0x9f9a:gōng # 龚 0x9f9b:kān # 龛 0x9f9c:guī,jūn,qiū # 龜 0x9f9d:qiū # 龝 0x9f9e:biē # 龞 0x9f9f:guī,jūn,qiū # 龟 0x9fa0:yuè # 龠 0x9fa1:chuī # 龡 0x9fa2:hé # 龢 0x9fa3:jiǎo # 龣 0x9fa4:xié # 龤 0x9fa5:yù # 龥 0x9fc3:shǎn # 鿃 0xf90e:lài,là # 癩 0xfa0c:wù,wū # 兀 0xfa0d:hù, huò # 嗀 0xfa10:zhǒng # 塚 0xfa12:qíng # 晴 0xfa15:xī # 凞 0xfa16:zhū # 猪 0xfa17:yì # 益 0xfa18:lǐ # 礼 0xfa19:shén # 神 0xfa1a:xiáng # 祥 0xfa1b:fú,fù # 福 0xfa1c:jìng # 靖 0xfa1d:jīng,qíng,jìng # 精 0xfa1e:yǔ # 羽 0xfa22:zhū # 諸 0xfa25:yì # 逸 0xfa26:dū # 都 0xfa2a:fàn # 飯 0xfa2b:sì # 飼 0xfa2c:guǎn # 館 0xfa2d:hè # 鶴 dtkcore-5.7.12/src/util/util.cmake000066400000000000000000000046231476226660600170100ustar00rootroot00000000000000if(LINUX) set(UTILS_SOURCES ${CMAKE_CURRENT_LIST_DIR}/dtimeunitformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/dabstractunitformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/ddisksizeformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbussender.cpp ${CMAKE_CURRENT_LIST_DIR}/drecentmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dnotifysender.cpp ${CMAKE_CURRENT_LIST_DIR}/dpinyin.cpp ${CMAKE_CURRENT_LIST_DIR}/dexportedinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/dvtablehook.cpp ${CMAKE_CURRENT_LIST_DIR}/dthreadutils.cpp ${CMAKE_CURRENT_LIST_DIR}/dtimedloop.cpp ${CMAKE_CURRENT_LIST_DIR}/dfileservices_linux.cpp ${CMAKE_CURRENT_LIST_DIR}/dexportedinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbusinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbusextendedabstractinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbusextendedpendingcallwatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dtextencoding.cpp ) else() set(UTILS_SOURCES ${CMAKE_CURRENT_LIST_DIR}/dtimeunitformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/dabstractunitformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/ddisksizeformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbussender.cpp ${CMAKE_CURRENT_LIST_DIR}/drecentmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/dnotifysender.cpp ${CMAKE_CURRENT_LIST_DIR}/dpinyin.cpp ${CMAKE_CURRENT_LIST_DIR}/dexportedinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/dvtablehook.cpp ${CMAKE_CURRENT_LIST_DIR}/dthreadutils.cpp ${CMAKE_CURRENT_LIST_DIR}/dtimedloop.cpp ${CMAKE_CURRENT_LIST_DIR}/dfileservices_dummy.cpp ${CMAKE_CURRENT_LIST_DIR}/dexportedinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbusinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbusextendedabstractinterface.cpp ${CMAKE_CURRENT_LIST_DIR}/ddbusextendedpendingcallwatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/dtextencoding.cpp ) endif() file(GLOB UTILS_HEADERS ${PROJECT_SOURCE_DIR}/include/util/*.h ) set(PRIVATE_HEADERS ${CMAKE_CURRENT_LIST_DIR}/ddbusinterface_p.h ${CMAKE_CURRENT_LIST_DIR}/ddbusextendedpendingcallwatcher_p.h) if(DTK_VERSION_MAJOR) list(REMOVE_ITEM UTILS_SOURCES "${CMAKE_CURRENT_LIST_DIR}/dtimedloop.cpp") list(REMOVE_ITEM UTILS_HEADERS "${PROJECT_SOURCE_DIR}/include/util/dtimedloop.h") # no longer be used list(REMOVE_ITEM UTILS_HEADERS "${PROJECT_SOURCE_DIR}/include/util/dasync.h") endif() set(utils_SRC ${UTILS_HEADERS} ${PRIVATE_HEADERS} ${UTILS_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/util.qrc ) dtkcore-5.7.12/src/util/util.qrc000066400000000000000000000001541476226660600165100ustar00rootroot00000000000000 resources/dpinyin.dict dtkcore-5.7.12/tests/000077500000000000000000000000001476226660600144225ustar00rootroot00000000000000dtkcore-5.7.12/tests/CMakeLists.txt000066400000000000000000000052521476226660600171660ustar00rootroot00000000000000# 方便 test 脚本中调用 set(BIN_NAME "ut-DtkCore") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) # dbus set(CMAKE_CXX_FLAGS "-fno-access-control") add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) if(LINUX) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus) find_package(PkgConfig REQUIRED) if("${QT_VERSION_MAJOR}" STREQUAL "5") pkg_check_modules(QGSettings REQUIRED IMPORTED_TARGET gsettings-qt) endif() endif() find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Xml) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Concurrent) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Test) find_package(GTest REQUIRED) # for test.so set(TEST_SO_NAME vtabletest${DTK_VERSION_MAJOR}) add_subdirectory(./testso) # test file(GLOB TEST_HEADER ut_.*h) file(GLOB TEST_SOURCE *.cpp) file(GLOB FackDBus "./fakedbus/*.h" "./fakedbus/*.cpp" ) if(DTK_VERSION_MAJOR) list(REMOVE_ITEM TEST_SOURCE "${CMAKE_CURRENT_LIST_DIR}/ut_gsettingsbackend.cpp") list(REMOVE_ITEM TEST_SOURCE "${CMAKE_CURRENT_LIST_DIR}/ut_dasync.cpp") endif() set(test_SRC ${TEST_HEADER} ${TEST_SOURCE} ${FackDBus} ) # end test add_executable(${BIN_NAME} ${test_SRC} ./data.qrc ) target_compile_definitions(${BIN_NAME} PUBLIC PREFIX="${DSG_PREFIX_PATH}" DSYSINFO_PREFIX="${DSYSINFO_PREFIX}" ) add_dependencies(${BIN_NAME} ${TEST_SO_NAME}) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::CorePrivate Qt${QT_VERSION_MAJOR}::Xml Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Test ${GTEST_LIBRARIES} ${LIB_NAME} -l${TEST_SO_NAME} ) if(LINUX) if(${QT_VERSION_MAJOR} STREQUAL "5") target_link_libraries( ${BIN_NAME} PRIVATE PkgConfig::QGSettings ) endif() target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::DBus -lpthread -lm -lgcov -ldl ) endif() #end LINUX target_link_directories(${BIN_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/testso/) target_include_directories( ${BIN_NAME} PUBLIC ../include/util/ ../include/dci/ ../include/log/ ../include/base/ ../include/base/private/ ../include/global/ ../include/DtkCore/ ../include/settings/ ../include/filesystem/ ../include/ ./testso/ ) add_test(NAME ${BIN_NAME} COMMAND ${BIN_NAME}) dtkcore-5.7.12/tests/data.qrc000066400000000000000000000012361476226660600160440ustar00rootroot00000000000000 data/dt-settings.json data/dconf-example.meta.json data/dconf-example.override.json data/dconf-override/dconf-example.override.a.json data/dconf-override/dconf-example.override.a.b.json data/dconf-global.meta.json data/dconf-global.override.json data/dconf-example_other_app_configure.meta.json data/LGPLv3.txt data/example-license.json data/dconf-example.override.noexistitem.json dtkcore-5.7.12/tests/data/000077500000000000000000000000001476226660600153335ustar00rootroot00000000000000dtkcore-5.7.12/tests/data/LGPLv3.txt000066400000000000000000000167171476226660600171170ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. dtkcore-5.7.12/tests/data/dconf-example.meta.json000077500000000000000000000054511476226660600217050ustar00rootroot00000000000000{ "magic": "dsg.config.meta", "version": "1.0", "contents": { "canExit": { "value": true, "serial": 0, "flags": ["global"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "private" }, "key2": { "value": "125", "serial": 0, "flags": ["nooverride"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "public" }, "key3": { "value": "application", "serial": 0, "flags": ["global"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "public" }, "number": { "value": 1, "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "numberDouble": { "value": 1.0, "serial": 0, "flags": ["global"], "name": "double value type", "permissions": "readwrite", "visibility": "public" }, "array": { "value": ["value1", "value2"], "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "array_map": { "value": [{"key1": "value1", "key2": "value2"}], "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "array_map_struct": { "value": [{"key1": {"field1": "value1"}, "key2": "value2"}], "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "map": { "value": {"key1": "value1", "key2": "value2"}, "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "map_array": { "value": {"key1": ["value1"], "key2": ["value2"]}, "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "struct": { "value": {"key1": "value1", "key2": "value2"}, "serial": 0, "flags": ["global"], "name": "array value type", "permissions": "readwrite", "visibility": "public" }, "publicConfig": { "value": true, "serial": 0, "flags": ["user-public"], "name": "public configure", "name[zh_CN]": "我是公开的配置", "description": "I am public configure", "permissions": "readwrite", "visibility": "private" } } } dtkcore-5.7.12/tests/data/dconf-example.override.json000066400000000000000000000002611476226660600225650ustar00rootroot00000000000000{ "magic": "dsg.config.override", "version": "1.0", "contents": { "key3": { "value": "override", "serial": 0, "permissions": "readwrite" } } } dtkcore-5.7.12/tests/data/dconf-example.override.noexistitem.json000066400000000000000000000002701476226660600251340ustar00rootroot00000000000000{ "magic": "dsg.config.override", "version": "1.0", "contents": { "noexistitem": { "value": "override", "serial": 0, "permissions": "readwrite" } } } dtkcore-5.7.12/tests/data/dconf-example_other_app_configure.meta.json000077500000000000000000000011351476226660600260020ustar00rootroot00000000000000{ "magic": "dsg.config.meta", "version": "1.0", "contents": { "appPublic": { "value": "publicValue", "serial": 0, "flags": ["global"], "name": "I am a public field for all application", "description": "I am description", "permissions": "readwrite", "visibility": "private" }, "appPrivate": { "value": "appPrivate", "serial": 0, "flags": ["nooverride"], "name": "I am a private field for the application", "description": "I am description", "permissions": "readwrite", "visibility": "public" } } } dtkcore-5.7.12/tests/data/dconf-global.meta.json000077500000000000000000000005151476226660600215060ustar00rootroot00000000000000{ "magic": "dsg.config.meta", "version": "1.0", "contents": { "key3": { "value": "global", "serial": 0, "flags": ["global"], "name": "I am name", "name[zh_CN]": "我是名字", "description": "I am description", "permissions": "readwrite", "visibility": "public" } } } dtkcore-5.7.12/tests/data/dconf-global.override.json000077500000000000000000000002571476226660600224020ustar00rootroot00000000000000{ "magic": "dsg.config.override", "version": "1.0", "contents": { "key3": { "value": "global", "serial": 0, "permissions": "readwrite" } } } dtkcore-5.7.12/tests/data/dconf-override/000077500000000000000000000000001476226660600202415ustar00rootroot00000000000000dtkcore-5.7.12/tests/data/dconf-override/dconf-example.override.a.b.json000077500000000000000000000002641476226660600261400ustar00rootroot00000000000000{ "magic": "dsg.config.override", "version": "1.0", "contents": { "key3": { "value": "override /a/b", "serial": 0, "permissions": "readwrite" } } } dtkcore-5.7.12/tests/data/dconf-override/dconf-example.override.a.json000077500000000000000000000002641476226660600257200ustar00rootroot00000000000000{ "magic": "dsg.config.override", "version": "1.0", "contents": { "key3": { "value": "override /a", "serial": 0, "permissions": "readwrite" } } } dtkcore-5.7.12/tests/data/dt-settings.json000066400000000000000000000171201476226660600204740ustar00rootroot00000000000000{ "groups": [ { "key": "base", "name": "Basic settings", "groups": [ { "key": "theme", "name": "Theme", "options": [ { "key": "theme", "type": "checkpicture", "default": 0 }, { "key": "opticy", "name": "Opticy", "type": "slider", "max": 100, "min": 0, "default": 90 } ] }, { "key": "font", "name": "Font Style", "options": [ { "key": "family", "name": "Font", "type": "combobox", "default": "" }, { "key": "size", "name": "Font Size", "type": "spinbutton", "default": 12 }, { "key": "style", "name": "Font Style", "type": "buttongroup", "items": ["B","/"], "default": 0 } ] } ] }, { "key": "shortcuts", "name": "Shortcuts", "groups": [ { "key": "ternimal", "name": "Ternimal", "options": [ { "key": "copy", "name": "Copy", "type": "shortcut", "default": "Ctrl+Alt+C" }, { "key": "paste", "name": "Paste", "type": "shortcut", "default": "Ctrl+Alt+V" }, { "key": "scroll_up", "name": "Scroll Up", "type": "shortcut", "default": "Alt+." }, { "key": "scroll_down", "name": "Scroll down", "type": "shortcut", "default": "Alt+," } ] }, { "key": "workspace", "name": "Workspace", "options": [ { "key": "new_window", "name": "New Window", "type": "shortcut", "default": "Ctrl+Shitf+<" }, { "key": "next_tab", "name": "Next Tab", "type": "shortcut", "default": "Ctrl+N" }, { "key": "prev_up", "name": "Previous Tab", "type": "shortcut", "default": "Ctrl+Shitf+>" }, { "key": "close_tab", "name": "Close Tab", "type": "shortcut", "default": "Ctrl+W" } ] } ] }, { "key": "advance", "name": "Advance", "groups": [ { "key": "cursor", "name": "Cursor", "options": [ { "key": "shrap", "name": "Cursor Shrap", "type": "buttongroup", "items": ["█","_","|"], "default": 0 }, { "key": "blink", "type": "checkbox", "text": "Cursor blink", "default": true }, { "key": "radiogroup", "name": " ", "type": "radiogroup", "items": ["Minimize to tray","Exit Deepin Music"], "default": 0 } ] }, { "key": "encoding", "name": "Default encoding", "options": [ { "key": "encoding", "name": "Encoding", "type": "combobox", "default": "utf-8" } ] }, { "key": "coustom", "name": "Coustom", "options": [ { "key": "coustom_command", "name": "Coustom Command", "type": "lineedit", "default": "" }, { "key": "coustom_directory", "name": "Coustom Directory", "type": "lineedit", "default": "" } ] }, { "key": "scroll", "name": "Scroll", "options": [ { "key": "scroll_bottom", "text": "Scroll Bottom", "type": "checkbox", "default": "" }, { "key": "scroll_line_count", "name": "Scroll line count", "type": "spinbutton", "default": 10 } ] }, { "key": "compatibility", "name": "Compatibility", "options": [ { "key": "breakspce_action", "name": "Breakspce Action", "type": "combobox", "default": "" }, { "key": "delete_action", "name": "Delete Action", "type": "combobox", "default": "" } ] } ] } ] } dtkcore-5.7.12/tests/data/example-license.json000066400000000000000000000002661476226660600213050ustar00rootroot00000000000000[ { "name": "dtk", "version": "5.6.8", "copyright": "Copyright 2023 The Uniontech Company Ltd. All rights reserved.", "license": "LGPLv3" } ] dtkcore-5.7.12/tests/fakedbus/000077500000000000000000000000001476226660600162065ustar00rootroot00000000000000dtkcore-5.7.12/tests/fakedbus/fakedbusservice.cpp000066400000000000000000000035301476226660600220600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "fakedbusservice.h" #include #include #include FakeDBusService::FakeDBusService(QObject *parent) : QObject(parent) , m_strproperty("testDBusService") , m_objectpaths({QDBusObjectPath("/ss"), QDBusObjectPath("/bb")}) { registerService(); } FakeDBusService::~FakeDBusService() { unregisterService(); } void FakeDBusService::registerService() { QDBusConnection bus = QDBusConnection::sessionBus(); if (!bus.registerService(m_service)) { QString errorMsg = bus.lastError().message(); if (errorMsg.isEmpty()) errorMsg = "maybe it's running"; qWarning() << QString("Can't register the %1 service, %2.").arg(m_service).arg(errorMsg); } if (!bus.registerObject(m_path, this, QDBusConnection::ExportScriptableContents)) { qWarning() << QString("Can't register %1 the D-Bus object.").arg(m_path); } } void FakeDBusService::unregisterService() { QDBusConnection bus = QDBusConnection::sessionBus(); bus.unregisterObject(m_path); bus.unregisterService(m_service); } FakeDBusServiceParent::FakeDBusServiceParent(QObject *parent) : QObject(parent) { m_dDbusFakeDBusServiceInter = new DDBusInterface(FakeDBusService::get_service(), FakeDBusService::get_path(), FakeDBusService::get_interface(), QDBusConnection::sessionBus(), this); } QList FakeDBusServiceParent::objectpaths() { return qvariant_cast>(m_dDbusFakeDBusServiceInter->property("objectPaths")); } dtkcore-5.7.12/tests/fakedbus/fakedbusservice.h000066400000000000000000000034221476226660600215250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include using Dtk::Core::DDBusInterface; class FakeDBusServiceParent: public QObject { Q_OBJECT public: explicit FakeDBusServiceParent(QObject *parent = nullptr); Q_PROPERTY(QList objectPaths READ objectpaths NOTIFY objectpathsChanged); QList objectpaths(); signals: void objectpathsChanged(); private: DDBusInterface *m_dDbusFakeDBusServiceInter; }; class FakeDBusService : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.deepin.FakeDBusService") public: explicit FakeDBusService(QObject *parent = nullptr); ~FakeDBusService(); Q_PROPERTY(QString strProperty READ strproperty WRITE setStrproperty) Q_PROPERTY(QList objectPaths READ objectpaths) static QString get_service() { return "org.deepin.FakeDBusService"; } static QString get_path() { return "/org/deepin/FakeDBusService"; } static QString get_interface() { return "org.deepin.FakeDBusService"; } public Q_SLOTS: inline QString strproperty() { return m_strproperty; } void setStrproperty(const QString &var) { if (var != m_strproperty) m_strproperty = var; } inline QList objectpaths() { return m_objectpaths; } // ExportScriptableContents Q_SCRIPTABLE QString foo() { return QString("bar"); } private: const QString m_service{"org.deepin.FakeDBusService"}; const QString m_path{"/org/deepin/FakeDBusService"}; void registerService(); void unregisterService(); QString m_strproperty; QList m_objectpaths; }; dtkcore-5.7.12/tests/main.cpp000066400000000000000000000013461476226660600160560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ut_dutil.h" #include #ifdef QT_DEBUG #include #endif int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setApplicationName("tests"); app.setOrganizationName("deepin"); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) DTimedLoop loop; #endif testing::InitGoogleTest(&argc, argv); int retVal = RUN_ALL_TESTS(); #ifdef QT_DEBUG __sanitizer_set_report_path("asan.log"); #endif #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) return loop.exec(0, "main execution") + retVal; #else return 0; #endif } dtkcore-5.7.12/tests/test-recoverage.sh000077500000000000000000000017321476226660600200630ustar00rootroot00000000000000#!/bin/bash # SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later set -ex BUILD_DIR=`pwd`/../build/tests/ HTML_DIR=${BUILD_DIR}/html XML_DIR=${BUILD_DIR}/report export ASAN_OPTIONS="halt_on_error=0" # back to project directroy cd .. cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=OFF -DEnableCov=ON -DDSYSINFO_PREFIX=/tmp cmake --build build -j$(nproc) cd $BUILD_DIR ./ut-DtkCore --gtest_output=xml:${XML_DIR}/report_dtkcore.xml # find *.gcda from build dir lcov -d ../ -c -o coverage_all.info lcov --remove coverage_all.info "*/tests/*" "*/usr/include*" "*build/src*" "*build-ut/src*" --output-file coverage.info cd .. genhtml -o $HTML_DIR $BUILD_DIR/coverage.info && mv ${BUILD_DIR}/html/index.html ${BUILD_DIR}/html/cov_dtkcore.html test -e ${BUILD_DIR}/asan.log* && mv ${BUILD_DIR}/asan.log* ${BUILD_DIR}/asan_dtkcore.log || touch ${BUILD_DIR}/asan.log dtkcore-5.7.12/tests/test_helper.hpp000066400000000000000000000027201476226660600174520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include class EnvGuard { public: void set(const char *name, const QByteArray &value, bool mkpath = true) { m_name = name; if (m_originValue.isEmpty()) m_originValue = qgetenv(m_name); qputenv(m_name, value); if (mkpath && !QDir(value).exists()) { QDir().mkpath(value); } } void unset(const char *name) { m_name = name; m_originValue = qgetenv(m_name); qunsetenv(m_name); } void restore() { qputenv(m_name, m_originValue); } QString value() { return qgetenv(m_name); } ~EnvGuard() { if (m_name) restore(); } private: QByteArray m_originValue; const char* m_name = nullptr; }; class FileGuard { public: explicit FileGuard(const QString &fileName) : m_fileName(fileName){ } virtual ~FileGuard() { QFile::remove(m_fileName); } const QString fileName() const { return m_fileName; } private: QString m_fileName; }; class FileCopyGuard : public FileGuard { public: FileCopyGuard(const QString &source, const QString &target) : FileGuard(target) { if (!QFile::exists(QFileInfo(target).path())) QDir().mkpath(QFileInfo(target).path()); QFile::copy(source, target); } }; dtkcore-5.7.12/tests/testso/000077500000000000000000000000001476226660600157435ustar00rootroot00000000000000dtkcore-5.7.12/tests/testso/CMakeLists.txt000066400000000000000000000005441476226660600205060ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later file(GLOB_RECURSE TESTSO "*.cpp" "*.h") add_compile_options(-fno-sanitize=all) add_link_options(-fno-sanitize=all) add_library(${TEST_SO_NAME} SHARED ${TESTSO}) target_link_libraries(${TEST_SO_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core) dtkcore-5.7.12/tests/testso/testso.cpp000066400000000000000000000003551476226660600177730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "testso.h" char TestClass::A::test(int v) { qDebug() << Q_FUNC_INFO << this << v; return 'a'; } dtkcore-5.7.12/tests/testso/testso.h000066400000000000000000000011301476226660600174300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include namespace TestClass { // test case use multiple inheritance struct A { int aa; virtual char test(int v); virtual ~A() {} }; struct B { int bx; virtual char test(int v) { qDebug() << Q_FUNC_INFO << v; return 'b'; } virtual ~B() {} }; struct C : public A, public B { int cx; char test(int v) override { qDebug() << Q_FUNC_INFO << v; return 'c'; } }; } // namespace TestClass dtkcore-5.7.12/tests/ut_dasync.cpp000066400000000000000000000207721476226660600171270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include "dasync.h" #include "dtimedloop.h" #include "ut_dutil.h" DCORE_USE_NAMESPACE #if 0 // 为了方便托管 std::thread 而创建的辅助类 class Thread : public QObject { std::thread *m_thread = nullptr; public: template Thread(FUNC &&func, QObject *parent = nullptr) : QObject (parent) , m_thread (new std::thread(func)) { } void detach() { m_thread->detach(); } void join() { m_thread->join(); } virtual ~Thread() { if (m_thread) { delete m_thread; m_thread = nullptr; } } }; bool gInSubFlag = true; // 全局内存托管,防止 asan 报错 QObject gRoot; template void DetachedRun(FUNC &&func) { Thread *thread = new Thread(func, &gRoot); if (!gInSubFlag) { func(); } thread->detach(); } class ut_DAsync : public testing::Test, public QObject { public: class Test : public QObject { public: Test(int in, QObject *parent = nullptr) : QObject (parent) , count (in) { } int count = 0; }; ut_DAsync() { } virtual ~ut_DAsync() {} virtual void SetUp() { task1 = new DAsync(this); // 测试 task2 在线程内部new能正常工作 task3 = new DAsync(this); // task4~task7 测试固定的API,功能大同小异,在函数内部创建 task8 = new DAsync(this); task9 = new DAsync(this); task10 = new DAsync(this); m_loop = new DTimedLoop(this); m_loop->setTimeDump(true); } virtual void TearDown() { // 释放资源要用 deleteLater 或者托管内存 // 避免线程不同步时直接 delete 导致 asan 偶发性报使用释放掉的堆内存 } // 首先要保证这些不同类型的模板参数的声明没有编译问题 DAsync *task1 = nullptr; DAsync *task2 = nullptr; DAsync *task3 = nullptr; DAsync *task4 = nullptr; DAsync *task5 = nullptr; DAsync *task6 = nullptr; // 第一个模板参数是 void 的类型的仅执行一次函数调用 DAsync *task7 = nullptr; DAsync *task8 = nullptr; DAsync *task9 = nullptr; DAsync *task10 = nullptr; // m_loop 须是 static 的,asan 会有误报 static DTimedLoop *m_loop; }; DTimedLoop *ut_DAsync::m_loop = nullptr; TEST_F(ut_DAsync, testRunInCorrectThread) { // 测试 post 中的函数一定在非主线程异步调用 // 返回结果传到 then 中的函数在主线程中调用 task1->post([](int arg) { HAVE_FUN(ASSERT_TRUE(!D_THREAD_IN_MAIN())); return arg; })->then([&](int arg) { ASSERT_EQ(arg, 1); HAVE_FUN(ASSERT_TRUE(D_THREAD_IN_MAIN())); m_loop->exit(); })->start(); task1->postData(1); m_loop->exec("testRunInCorrectThread"); } TEST_F(ut_DAsync, testRunInSubThread) { // 和上面 testRunInCorrectThread 测项类似 // task2, 测试 task 在非主线程中依然能正确创建和运行 bool startedFlag = false; DetachedRun([&]{ // 这里用托管也可以的,但是会有警告 task2 = new DAsync(/*this*/); task2->post([](int arg) { HAVE_FUN(ASSERT_TRUE(!D_THREAD_IN_MAIN())); return arg; })->then([&](int arg) { static int i = 0; ASSERT_EQ(arg, i++); HAVE_FUN(ASSERT_TRUE(D_THREAD_IN_MAIN())); if (i > 3) m_loop->exit(); })->start(); startedFlag = true; }); DetachedRun([&]{ static int i = 0; while (true) { // 要自己设置 flag,因为在不同的线程中, // 到这里 task2 还不一定已经被创建完毕 if (startedFlag) { task2->postData(i++); if (i > 3) { break; } } usleep(100*1000); } }); m_loop->exec("testRunInSubThread"); } TEST_F(ut_DAsync, testMultiThreadSynchronization) { // task3, 在子线程中输入 0~999, 在 post 中乘以 2 输出到主线程 then 中 static int n = 1000; static int result = 0; task3->post([](int arg) -> QString { return QString("%1").arg(arg * 2); })->then([](QString arg) { static int i = 0; ASSERT_TRUE(arg == QString("%1").arg(i * 2)); i++; result = n; })->start(); DetachedRun([&] { int i = 0; while (i < n) { if (!task3->isFinished()) { task3->postData(i++); } } task3->cancelAll(); }); DetachedRun([&] { // 该线程启动后会一直阻塞等待,直到 cancelAll 被调用, // 说明任务结束了,就可以往下走,判断执行结果 task3->waitForFinished(false); ASSERT_EQ(result, n); m_loop->exit(); }); m_loop->exec("testMultiThreadSynchronization"); } TEST_F(ut_DAsync, testOneTimeTask) { // task8, 测试一次性任务,确保两个函数只会进来执行一次 task8->post([] { static int i = 0; return QString("testOneTimeTask%1").arg(i++); })->then([&](const QString &arg) { ASSERT_TRUE(arg == "testOneTimeTask0"); m_loop->exit(); })->start(); m_loop->exec("test task8"); // task9, 测试一次性任务,确保只有 post 的函数能够被执行到 task9->post([&]{ m_loop->exit(); })->start(); // task9->startUp(); # 或者在合适的时候调用 m_loop->exec("test task9"); // task10, 测试仅有 post 的任务的正确执行 task10->post([&] (int arg) { static int j = 0; ASSERT_EQ(arg, j++); if (j == 2) { m_loop->exit(); } }); task10->postData(0); task10->startUp(); task10->postData(1); m_loop->exec("test task10"); } TEST_F(ut_DAsync, testFixedApi) { // 测试这些固定的 API 能够正确处理不同的参数类型 // task4 task4 = new DAsync(this); static int i = 0; while (i < 100) { task4->postData(QString::number(i++)); } task4->post([](const QString &arg) -> QString { static int j = 0; HAVE_FUN(ASSERT_TRUE(arg == QString::number(j++))); return arg; })->then([](QString arg) { static int k = 0; ASSERT_TRUE(arg == QString::number(k++)); if (k == 100) { m_loop->exit(); } })->start(); m_loop->exec("test task4"); // 和上面的不一样的地方就是 postData 在 start 前后都调用了 // task5 i = 0; task5 = new DAsync(this); while (i < 50) { task5->postData(new Test(i++, this)); } task5->post([](Test *arg) -> Test * { static int j = 0; HAVE_FUN(ASSERT_TRUE(arg->count == j++)); return arg; })->then([](Test *arg) { static int k = 0; HAVE_FUN(ASSERT_TRUE(arg->count == k++)); if (k == 100) { m_loop->exit(); } })->start(); while (i < 100) { task5->postData(new Test(i++, this)); } m_loop->exec("test task5"); // task6 i = 0; task6 = new DAsync(this); while (i < 50) { task6->postData(QString::number(i++)); } task6->post([](QString arg) { static int j = 0; HAVE_FUN(ASSERT_TRUE(arg == QString::number(j++))); })->then([]() { static int k = 0; k++; if (k == 100) { m_loop->exit(); } })->start(false); DetachedRun([&]{ usleep(100 * 1000); while (i < 100) { task6->postData(QString::number(i++)); } task6->startUp(); }); m_loop->exec("test task6"); // task7 task7 = new DAsync(this); task7->post([]() { static int j = 0; HAVE_FUN(ASSERT_TRUE(0 == j++)); })->then([]() { static int k = 0; HAVE_FUN(ASSERT_TRUE(0 == k++)); m_loop->exit(); })->start(); m_loop->exec("test task7"); } #endif dtkcore-5.7.12/tests/ut_dcapfile.cpp000066400000000000000000000111711476226660600174060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "filesystem/dcapmanager.h" #include "filesystem/dcapfile.h" #include #include #include #include DCORE_USE_NAMESPACE #ifndef GTEST_SKIP #define SKIP return GTEST_SUCCEED() << "Skip all tests" #else #define SKIP GTEST_SKIP() << "Skip all tests" #endif #define TMPCAP_PATH "/tmp/cap" class ut_DCapFile : public testing::Test { protected: void SetUp() override; void TearDown() override; DCapManager *manager; QFile *file; }; void ut_DCapFile::SetUp() { manager = DCapManager::instance(); manager->removePath("/tmp"); manager->appendPath(TMPCAP_PATH); file = new QFile(nullptr); QDir dir(TMPCAP_PATH); if (!dir.exists()) ASSERT_TRUE(dir.mkdir(TMPCAP_PATH)); } void ut_DCapFile::TearDown() { manager->appendPath("/tmp"); delete file; QDir dir(TMPCAP_PATH); if (dir.exists()) ASSERT_TRUE(dir.removeRecursively()); } TEST(ut_DCapManager, paths) { auto size = DCapManager::instance()->paths().size(); EXPECT_TRUE(size > 0); DCapManager::instance()->appendPaths({"/path/to/myCap"}); EXPECT_TRUE(DCapManager::instance()->paths().contains("/path/to/myCap")); DCapManager::instance()->removePaths({"/path/to/myCap"}); EXPECT_FALSE(DCapManager::instance()->paths().contains("/path/to/myCap")); } TEST(ut_DCapFileAndDir, testDCapFileOpen) { DCapFile file("/tmp/test0"); ASSERT_TRUE(file.open(DCapFile::WriteOnly)); // Default, '/tmp' is allowable for writing. file.close(); DCapManager::instance()->removePath("/tmp"); ASSERT_FALSE(file.open(DCapFile::WriteOnly)); DCapManager::instance()->appendPath("/tmp"); } TEST(ut_DCapFileAndDir, testDCapFileOperation) { auto CheckResult = [](bool result) { DCapFile file("/tmp/test0"); ASSERT_EQ(file.open(DCapFile::WriteOnly), result); file.close(); ASSERT_EQ(file.exists(), result); ASSERT_EQ(DCapFile::exists(file.fileName()), result); ASSERT_EQ(file.remove(), result); ASSERT_EQ(file.open(DCapFile::WriteOnly), result); file.close(); ASSERT_EQ(DCapFile::remove(file.fileName()), result); ASSERT_EQ(file.open(DCapFile::WriteOnly), result); file.close(); ASSERT_EQ(file.rename("/tmp/test1"), result); ASSERT_EQ(DCapFile::rename(file.fileName(), "/tmp/test0"), result); file.setFileName("/tmp/test0"); ASSERT_EQ(file.link("/tmp/test_link0"), result); ASSERT_EQ(DCapFile::link(file.fileName(), "/tmp/test_link1"), result); ASSERT_EQ(DCapFile::remove("/tmp/test_link0"), result); ASSERT_EQ(DCapFile::remove("/tmp/test_link1"), result); file.setFileName("/tmp/test0"); ASSERT_EQ(file.copy("/tmp/test_copy0"), result); ASSERT_EQ(DCapFile::copy(file.fileName(), "/tmp/test_copy1"), result); ASSERT_EQ(DCapFile::remove("/tmp/test_copy0"), result); ASSERT_EQ(DCapFile::remove("/tmp/test_copy1"), result); ASSERT_EQ(file.resize(10), result); ASSERT_EQ(file.size() == 10, result); ASSERT_EQ(DCapFile::resize(file.fileName(), 5), result); ASSERT_EQ(file.size() == 5, result); ASSERT_EQ(file.remove(), result); }; CheckResult(true); DCapManager::instance()->removePath("/tmp"); CheckResult(false); DCapManager::instance()->appendPath("/tmp"); } TEST(ut_DCapFileAndDir, testDCapDirOperation) { DCapDir dir("/tmp"); ASSERT_TRUE(dir.exists()); ASSERT_FALSE(dir.entryList().isEmpty()); ASSERT_FALSE(dir.entryInfoList().isEmpty()); DCapFile file(dir.path() + "/test0"); ASSERT_TRUE(file.open(DCapFile::WriteOnly)); file.close(); ASSERT_TRUE(dir.exists("test0")); ASSERT_TRUE(dir.mkdir("cap")); ASSERT_TRUE(dir.exists("cap")); ASSERT_TRUE(dir.rmdir("cap")); ASSERT_FALSE(dir.exists("cap")); dir.mkdir("cap"); ASSERT_TRUE(dir.cd("cap")); ASSERT_TRUE(dir.exists()); DCapManager::instance()->removePath("/tmp"); DCapManager::instance()->appendPath(dir.path()); ASSERT_FALSE(dir.cd("..")); dir.setPath("/tmp"); ASSERT_TRUE(dir.entryList().isEmpty()); ASSERT_TRUE(dir.entryInfoList().isEmpty()); ASSERT_TRUE(dir.exists("cap")); ASSERT_FALSE(dir.remove("test0")); ASSERT_FALSE(dir.rename("test0", "test1")); ASSERT_TRUE(dir.mkpath(TMPCAP_PATH"/subdir")); ASSERT_TRUE(dir.rmpath(TMPCAP_PATH"/subdir")); DCapManager::instance()->appendPath("/tmp"); ASSERT_TRUE(dir.rename("test0", "test1")); ASSERT_TRUE(dir.remove("test1")); } dtkcore-5.7.12/tests/ut_dconfig.cpp000066400000000000000000000162151476226660600172540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "test_helper.hpp" #include "backend/dsettingsdconfigbackend.h" DCORE_USE_NAMESPACE static EnvGuard dsgDataDir; static constexpr char const *APP_ID = "tests"; static constexpr char const *FILE_NAME = "example"; class ut_DConfig : public testing::Test { protected: static void SetUpTestCase() { fileBackendLocalPerfix.set("DSG_DCONFIG_FILE_BACKEND_LOCAL_PREFIX", "/tmp/example"); backendType.set("DSG_DCONFIG_BACKEND_TYPE", "FileBackend"); dsgDataDir.set("DSG_DATA_DIRS", PREFIX"/share/dsg"); } static void TearDownTestCase() { QDir(fileBackendLocalPerfix.value()).removeRecursively(); fileBackendLocalPerfix.restore(); backendType.restore(); dsgDataDir.restore(); } virtual void SetUp() override {} virtual void TearDown() override; static EnvGuard backendType; static EnvGuard fileBackendLocalPerfix; QString metaFilePath = QString("%1" PREFIX"/share/dsg/configs/%2/%3.json").arg(fileBackendLocalPerfix.value(), APP_ID, FILE_NAME); QString noAppIdMetaFilePath = QString("%1" PREFIX"/share/dsg/configs/%2.json").arg(fileBackendLocalPerfix.value(), FILE_NAME); }; EnvGuard ut_DConfig::fileBackendLocalPerfix; EnvGuard ut_DConfig::backendType; void ut_DConfig::TearDown() { QDir(fileBackendLocalPerfix.value()).removeRecursively(); } TEST_F(ut_DConfig, backend) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); DConfig config(FILE_NAME); ASSERT_EQ(config.backendName(), QString("FileBackend")); } TEST_F(ut_DConfig, isValid) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); DConfig config(FILE_NAME); ASSERT_TRUE(config.isValid()); } TEST_F(ut_DConfig, value) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); const QStringList array{"1", "2"}; QVariantMap map; map.insert("key1", "value1"); map.insert("key2", "value2"); { DConfig config(FILE_NAME); config.setValue("key2", "126"); ASSERT_EQ(config.value("key2").toString(), QString("126")); config.setValue("array", array); ASSERT_EQ(config.value("array").toStringList(), array); config.setValue("map", map); ASSERT_EQ(config.value("map").toMap(), map); } { DConfig config(FILE_NAME); ASSERT_EQ(config.value("key2").toString(), QString("126")); ASSERT_EQ(config.value("array").toStringList(), array); ASSERT_EQ(config.value("map").toMap(), map); } { DConfig config(FILE_NAME); config.reset("canExit"); ASSERT_EQ(config.value("canExit").toBool(), true); config.reset("key2"); ASSERT_EQ(config.value("key2").toString(), QString("125")); config.reset("number"); ASSERT_EQ(config.value("number").toInt(), 1); config.reset("array"); const QStringList &originArray {"value1", "value2"}; ASSERT_EQ(config.value("array").toStringList(), originArray); config.reset("map"); QVariantMap originMap; originMap.insert("key1", "value1"); originMap.insert("key2", "value2"); ASSERT_EQ(config.value("map").toMap(), originMap); } } TEST_F(ut_DConfig, keyList) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); DConfig config(FILE_NAME); QStringList keyList{QString("key2"), QString("canExit")}; for (auto item : keyList) { ASSERT_TRUE(config.keyList().contains(item)); } } TEST_F(ut_DConfig, OtherAppConfigfile) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); constexpr char const *APP_OTHER = "tests_other"; FileCopyGuard gurand(":/data/dconf-example_other_app_configure.meta.json", QString("%1" PREFIX"/share/dsg/configs/%2/%3.json").arg(fileBackendLocalPerfix.value(), APP_OTHER, FILE_NAME)); QScopedPointer config(DConfig::create(APP_OTHER, FILE_NAME)); ASSERT_TRUE(config->isValid()); ASSERT_EQ(config->value("appPublic").toString(), QString("publicValue")); } TEST_F(ut_DConfig, appIdWriteConfig) { FileCopyGuard guard(":/data/dconf-example.meta.json", noAppIdMetaFilePath); { // 内部会传递appid,强制appid不为空 DConfig config(FILE_NAME); config.setValue("key2", "user-with-appid"); ASSERT_EQ(config.value("key2"), "user-with-appid"); } { // appid为公共id QScopedPointer config(DConfig::createGeneric(FILE_NAME)); ASSERT_TRUE(config->isValid()); ASSERT_EQ(config->value("key2").toString(), QString("125")); } { // 传递appid QScopedPointer config(DConfig::create(APP_ID, FILE_NAME)); ASSERT_TRUE(config->isValid()); ASSERT_EQ(config->value("key2").toString(), "user-with-appid"); } } TEST_F(ut_DConfig, noAppidWirteConfig) { FileCopyGuard guard(":/data/dconf-example.meta.json", noAppIdMetaFilePath); FileCopyGuard guard2(":/data/dconf-example.meta.json", metaFilePath); { // 内部会传递appid,强制appid不为公共id QScopedPointer config(DConfig::createGeneric(FILE_NAME)); ASSERT_TRUE(config->isValid()); config->setValue("key2", "user-with-no-appid"); ASSERT_EQ(config->value("key2"), "user-with-no-appid"); } { // appid为公共id,获取公共id的值 QScopedPointer config(DConfig::createGeneric(FILE_NAME)); ASSERT_EQ(config->value("key2"), "user-with-no-appid"); } { // 传递appid,fallback到公共id的值 QScopedPointer config(DConfig::create(APP_ID, FILE_NAME)); ASSERT_EQ(config->value("key2"), "user-with-no-appid"); } } TEST_F(ut_DConfig, DSettingsDConfigBackend) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); { DSettingsDConfigBackend backend(FILE_NAME); QStringList keyList{ QString("key2"), QString("canExit") }; for (auto item : keyList) { ASSERT_TRUE(backend.keys().contains(item)); } } { DSettingsDConfigBackend backend(FILE_NAME); ASSERT_EQ(backend.getOption("key2").toString(), QString("125")); } { DConfig config(FILE_NAME); config.setValue("key2", "126"); // save cache file } { // reload cache file DSettingsDConfigBackend backend(FILE_NAME); ASSERT_EQ(backend.getOption("key2").toString(), QString("126")); } } TEST_F(ut_DConfig, isDefaultValue) { FileCopyGuard guard(":/data/dconf-example.meta.json", metaFilePath); { DConfig config(FILE_NAME); ASSERT_EQ(config.isDefaultValue("key2"), true); } { DConfig config(FILE_NAME); config.setValue("key2", "126"); EXPECT_EQ(config.isDefaultValue("key2"), false); } { DConfig config(FILE_NAME); config.setValue("key2", "126"); config.reset("key2"); EXPECT_EQ(config.isDefaultValue("key2"), true); } } dtkcore-5.7.12/tests/ut_dconfigfile.cpp000066400000000000000000000555651476226660600201270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "test_helper.hpp" #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) #define type typeId // In qt6 type is deprecated and typeId should be used, this macro is for more convenient compatibility with qt6 #endif DCORE_USE_NAMESPACE static constexpr char const *LocalPrefix = "/tmp/example"; static QString NoAppId; class ut_DConfigFile : public testing::Test { protected: static void SetUpTestCase() { home.set("HOME", "/tmp/home"); dsgDataDir.set("DSG_DATA_DIRS", PREFIX"/share/dsg"); } static void TearDownTestCase() { dsgDataDir.restore(); home.restore(); } virtual void TearDown() override; const char *APP_ID = "org.foo.appid"; const char *FILE_NAME = "org.foo.name"; QString metaPath = QString("%1" PREFIX"/share/dsg/configs/%2").arg(LocalPrefix, APP_ID); QString metaGlobalPath = QString("%1" PREFIX"/share/dsg/configs").arg(LocalPrefix); QString overridePath = QString("%1" PREFIX"/share/dsg/configs/overrides/%2/%3").arg(LocalPrefix, APP_ID, FILE_NAME); const char *OTHER_APP_ID = "tests_other"; QString noAppidMetaPath = QString("%1" PREFIX"/share/dsg/configs").arg(LocalPrefix); QString noAppidOverridePath = QString("%1" PREFIX"/share/dsg/configs/overrides/%2").arg(LocalPrefix, FILE_NAME); uint uid = getuid(); static EnvGuard dsgDataDir; static EnvGuard home; }; EnvGuard ut_DConfigFile::dsgDataDir; EnvGuard ut_DConfigFile::home; void ut_DConfigFile::TearDown() { QDir(LocalPrefix).removeRecursively(); } TEST_F(ut_DConfigFile, testLoad) { QByteArray meta = R"delimiter( { "magic": "dsg.config.meta", "version": "1.0", "contents": { "canExit": { "value": false, "serial": 0, "name": "I am name", "name[zh_CN]": "我是名字", "description": "我是描述", "description[en_US]": "I am description", "permissions": "readwrite", "visibility": "private" } } } )delimiter"; QBuffer buffer; buffer.setData(meta); DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(&buffer, {})); ASSERT_EQ(config.meta()->keyList(), QStringList{QLatin1String("canExit")}); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_EQ(config.value("canExit", userCache.get()).toBool(), false); ASSERT_EQ(config.meta()->version().major, 1); ASSERT_EQ(config.meta()->version().minor, 0); ASSERT_EQ(config.meta()->visibility("canExit"), DConfigFile::Private); ASSERT_EQ(config.meta()->displayName("canExit", QLocale::AnyLanguage), "I am name"); ASSERT_EQ(config.meta()->displayName("canExit", QLocale::Chinese), QString("我是名字")); ASSERT_EQ(config.meta()->description("canExit", QLocale::AnyLanguage), "我是描述"); ASSERT_EQ(config.meta()->description("canExit", QLocale::English), "I am description"); ASSERT_EQ(config.meta()->permissions("canExit"), DConfigFile::ReadWrite); } TEST_F(ut_DConfigFile, setValueTypeCheck) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); { const auto type = config.value("canExit", userCache.get()).type(); ASSERT_TRUE(config.setValue("canExit", false, "test", userCache.get())); ASSERT_TRUE(config.setValue("canExit", "true", "test", userCache.get())); ASSERT_FALSE(config.setValue("canExit", "true2", "test", userCache.get())); ASSERT_EQ(config.value("canExit", userCache.get()).type(), type); } { const auto type = config.value("key2", userCache.get()).type(); ASSERT_TRUE(config.setValue("key2", "121", "test", userCache.get())); ASSERT_FALSE(config.setValue("key2", 121, "test", userCache.get())); ASSERT_EQ(config.value("key2", userCache.get()).type(), type); } { const auto type = config.value("number", userCache.get()).type(); ASSERT_TRUE(config.setValue("number", 1, "test", userCache.get())); ASSERT_TRUE(config.setValue("number", 2.0, "test", userCache.get())); ASSERT_TRUE(config.setValue("number", "3", "test", userCache.get())); ASSERT_FALSE(config.setValue("number", "1ab", "test", userCache.get())); ASSERT_EQ(config.value("number", userCache.get()).type(), type); } { const auto type = config.value("numberDouble", userCache.get()).type(); ASSERT_TRUE(config.setValue("numberDouble", 1.2, "test", userCache.get())); ASSERT_EQ(config.value("numberDouble", userCache.get()), 1.2); } { const auto type = config.value("array", userCache.get()).type(); const QStringList array{"value1", "value2"}; ASSERT_TRUE(config.setValue("array", QStringList(), "test", userCache.get())); ASSERT_TRUE(config.setValue("array", array, "test", userCache.get())); ASSERT_TRUE(config.setValue("array", QJsonDocument::fromJson("[]").toVariant(), "test", userCache.get())); ASSERT_FALSE(config.setValue("array", "", "test", userCache.get())); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ASSERT_FALSE(config.setValue("array", "value1", "test", userCache.get())); #else ASSERT_TRUE(config.setValue("array", "value1", "test", userCache.get())); #endif ASSERT_EQ(config.value("array", userCache.get()).type(), type); } { const auto type = config.value("array_map", userCache.get()).type(); QVariantList array; QVariantMap map1; map1["key1"] = "value1"; map1["key2"] = "value2"; array.append(map1); ASSERT_EQ(config.value("array_map", userCache.get()).toList(), array); ASSERT_TRUE(config.setValue("array_map", QVariantList(), "test", userCache.get())); ASSERT_TRUE(config.setValue("array_map", array, "test", userCache.get())); ASSERT_TRUE(config.setValue("array_map", QJsonDocument::fromJson("[]").toVariant(), "test", userCache.get())); ASSERT_FALSE(config.setValue("array_map", "", "test", userCache.get())); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ASSERT_FALSE(config.setValue("array_map", "value1", "test", userCache.get())); #else ASSERT_TRUE(config.setValue("array_map", "value1", "test", userCache.get())); #endif ASSERT_EQ(config.value("array_map", userCache.get()).type(), type); } { const auto type = config.value("map", userCache.get()).type(); QVariantMap map; map.insert("key1", "value1"); map.insert("key2", "value2"); ASSERT_TRUE(config.setValue("map", QVariantMap(), "test", userCache.get())); ASSERT_TRUE(config.setValue("map", map, "test", userCache.get())); ASSERT_TRUE(config.setValue("map", QJsonDocument::fromJson("{}").toVariant(), "test", userCache.get())); ASSERT_FALSE(config.setValue("map", QJsonDocument::fromJson("[]").toVariant(), "test", userCache.get())); ASSERT_FALSE(config.setValue("map", "key1", "test", userCache.get())); ASSERT_EQ(config.value("map", userCache.get()).type(), type); } { const auto type = config.value("map_array", userCache.get()).type(); QVariantMap map; map.insert("key1", QStringList{"value1"}); map.insert("key2", QStringList{"value2"}); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ASSERT_EQ(config.value("map_array", userCache.get()).toMap(), map); #else auto ret = config.value("map_array", userCache.get()).toMap(); ASSERT_EQ(ret.keys(), map.keys()); auto value1 = ret.values(); auto value2 = map.values(); ASSERT_EQ(value1.size(), value2.size()); for(std::size_t i = 0; i < value1.size(); ++i){ ASSERT_EQ(value1[i].toStringList(), value2[i].toStringList()); } #endif ASSERT_TRUE(config.setValue("map_array", QVariantMap(), "test", userCache.get())); ASSERT_TRUE(config.setValue("map_array", map, "test", userCache.get())); ASSERT_TRUE(config.setValue("map_array", QJsonDocument::fromJson("{}").toVariant(), "test", userCache.get())); ASSERT_FALSE(config.setValue("map_array", "", "test", userCache.get())); ASSERT_FALSE(config.setValue("map_array", "value1", "test", userCache.get())); ASSERT_EQ(config.value("map_array", userCache.get()).type(), type); } } TEST_F(ut_DConfigFile, fileIODevice) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); } { DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); config.setValue("canExit", false, "test", userCache.get()); config.setValue("key2", QString("128"), "test", userCache.get()); ASSERT_TRUE(config.save(LocalPrefix)); ASSERT_TRUE(userCache->save(LocalPrefix)); } { DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("canExit", userCache.get()), false); ASSERT_EQ(config.value("key2", userCache.get()).toString(), QString("128")); } } TEST_F(ut_DConfigFile, appmeta) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()).toString(), QString("application")); } } TEST_F(ut_DConfigFile, globalmeta) { FileCopyGuard guard(":/data/dconf-global.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()), QString("global")); } TEST_F(ut_DConfigFile, meta) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); FileCopyGuard guard2(":/data/dconf-global.meta.json", QString("%1/%2.json").arg(metaGlobalPath, FILE_NAME)); DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()), QString("application")); const QStringList array{"value1", "value2"}; ASSERT_EQ(config.value("array", userCache.get()).toStringList(), array); QVariantMap map; map.insert("key1", "value1"); map.insert("key2", "value2"); ASSERT_EQ(config.value("map", userCache.get()).toMap(), map); } TEST_F(ut_DConfigFile, fileOverride) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()), QString("application")); } FileCopyGuard guard1(":/data/dconf-example.override.json", QString("%1/%2.json").arg(overridePath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()), QString("override")); } FileCopyGuard guard2(":/data/dconf-override/dconf-example.override.a.json", QString("%1/a/%2.json").arg(overridePath, FILE_NAME)); { { DConfigFile config(APP_ID, FILE_NAME, "/a"); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()).toString(), QString("override /a")); } } FileCopyGuard guard3(":/data/dconf-override/dconf-example.override.a.b.json", QString("%1/a/b/%2.json").arg(overridePath, FILE_NAME)); { { DConfigFile config(APP_ID, FILE_NAME, "/a/b"); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key3", userCache.get()).toString(), QString("override /a/b")); } } } TEST_F(ut_DConfigFile, fileOverrideNoExistItem) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); FileCopyGuard guard2(":/data/dconf-example.override.noexistitem.json", QString("%1/%2.json").arg(overridePath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); ASSERT_FALSE(config.meta()->keyList().contains("noexistitem")); } } TEST_F(ut_DConfigFile, noAppIdWithGlobalConfiguration) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(noAppidMetaPath, FILE_NAME)); { DConfigFile config(NoAppId, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); ASSERT_EQ(config.value("key3"), QString("application")); config.setValue("key3", "global-with-no-appid", "test"); config.save(LocalPrefix); } { DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); ASSERT_EQ(config.value("key3"), "global-with-no-appid"); } } TEST_F(ut_DConfigFile, noAppIdWithUserConfiguration) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(noAppidMetaPath, FILE_NAME)); { DConfigFile config(NoAppId, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key2", userCache.get()), QString("125")); config.setValue("key2", "user-with-no-appid", "test", userCache.get()); ASSERT_TRUE(userCache->save(LocalPrefix)); } { DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); ASSERT_EQ(config.value("key2", userCache.get()), "user-with-no-appid"); } } TEST_F(ut_DConfigFile, noAppIdUserConfiguration) { // meta安装在公共目录,使用空的appid设置配置项, 则无论是否传入appid,获取的是均为空appid的cache值 FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(noAppidMetaPath, FILE_NAME)); { // 不传入appid设置配置项 DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); config.setValue("key2", "user-with-no-appid", "test", userCache.get()); userCache->save(LocalPrefix); } { // 不传入appid,获取的为空appid的值 DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); ASSERT_EQ(config.value("key2", userCache.get()), "user-with-no-appid"); } } TEST_F(ut_DConfigFile, appIdOverrideNoAppIdUserConfiguration) { // meta安装在公共目录,appid覆盖了meta文件,使用空的appid设置配置项, 则无论是否传入appid,获取的是均为空appid的cache值 FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(noAppidMetaPath, FILE_NAME)); FileCopyGuard guard2(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); config.setValue("key2", "user-with-no-appid", "test", userCache.get()); userCache->save(LocalPrefix); } { // 不传入appid,获取的为空appid的值 DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); ASSERT_EQ(config.value("key2", userCache.get()), "user-with-no-appid"); } { // 传入appid设置配置项 DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); config.setValue("key2", "user-with-appid", "test", userCache.get()); userCache->save(LocalPrefix); } { // 不传入appid,获取的是空appid的值 DConfigFile config(NoAppId, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); ASSERT_EQ(config.value("key2", userCache.get()), "user-with-no-appid"); } { // 传入appid,获取的是含appid的值 DConfigFile config(APP_ID, FILE_NAME); config.load(LocalPrefix); QScopedPointer userCache(config.createUserCache(uid)); userCache->load(LocalPrefix); ASSERT_EQ(config.value("key2", userCache.get()).toString().toStdString(), "user-with-appid"); } } TEST_F(ut_DConfigFile, setCachePathPrefix) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); config.globalCache()->setCachePathPrefix("/configs-global"); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); userCache->setCachePathPrefix("/configs-user"); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key2", userCache.get()), QString("125")); ASSERT_EQ(config.value("key3", userCache.get()), QString("application")); config.setValue("key2", QString("user-config"), "test", userCache.get()); config.setValue("key3", "global-config", "test", userCache.get()); config.save(LocalPrefix); userCache->save(LocalPrefix); } { DConfigFile config(APP_ID, FILE_NAME); config.globalCache()->setCachePathPrefix("/configs-global"); ASSERT_TRUE(config.load(LocalPrefix)); QScopedPointer userCache(config.createUserCache(uid)); userCache->setCachePathPrefix("/configs-user"); ASSERT_TRUE(userCache->load(LocalPrefix)); ASSERT_EQ(config.value("key2", userCache.get()), QString("user-config")); ASSERT_EQ(config.value("key3", userCache.get()), QString("global-config")); } } TEST_F(ut_DConfigFile, setSubpath) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); } { DConfigFile config(APP_ID, FILE_NAME, "/a/b"); ASSERT_TRUE(config.load(LocalPrefix)); } { DConfigFile config(APP_ID, FILE_NAME, "/a/b/.."); ASSERT_TRUE(config.load(LocalPrefix)); } { DConfigFile config(APP_ID, FILE_NAME, "/../a/b"); ASSERT_FALSE(config.load(LocalPrefix)); } { DConfigFile config(APP_ID, FILE_NAME, "/a/b/../../.."); ASSERT_FALSE(config.load(LocalPrefix)); } } TEST_F(ut_DConfigFile, userPublic) { FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); { DConfigFile config(APP_ID, FILE_NAME); ASSERT_TRUE(config.load(LocalPrefix)); ASSERT_TRUE(config.meta()->flags("publicConfig").testFlag(DConfigFile::UserPublic)); ASSERT_FALSE(config.meta()->flags("canExit").testFlag(DConfigFile::UserPublic)); } } class ut_DConfigFileCheckName : public ut_DConfigFile, public ::testing::WithParamInterface> { }; TEST_P(ut_DConfigFileCheckName, checkName) { const auto [fileName, isValid] = GetParam(); FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, fileName)); DConfigFile config(APP_ID, fileName); ASSERT_EQ(config.load(LocalPrefix), isValid); } INSTANTIATE_TEST_SUITE_P(checkName, ut_DConfigFileCheckName, ::testing::Values( std::tuple{QString("org-foo"), true}, std::tuple{QString("org foo"), true}, std::tuple{QString("org.foo2"), true}, std::tuple{QString("org/foo"), false}, std::tuple{QString("./org-foo"), false}, std::tuple{QString("../configs/org-foo"), false})); class ut_DConfigFileCheckAppId : public ut_DConfigFile, public ::testing::WithParamInterface> { }; TEST_P(ut_DConfigFileCheckAppId, checkAppId) { const auto [appId, isValid] = GetParam(); FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2/%3.json").arg(noAppidMetaPath, appId, FILE_NAME)); DConfigFile config(appId, FILE_NAME); ASSERT_EQ(config.load(LocalPrefix), isValid); } INSTANTIATE_TEST_SUITE_P(checkAppId, ut_DConfigFileCheckAppId, ::testing::Values( std::tuple{NoAppId, true}, std::tuple{QString("org-foo"), true}, std::tuple{QString("org foo"), false}, std::tuple{QString("org.foo2"), true}, std::tuple{QString("org/foo"), false}, std::tuple{QString("./org-foo"), false}, std::tuple{QString("../configs/org-foo"), false})); dtkcore-5.7.12/tests/ut_ddbusextendedabstractinterface.cpp000066400000000000000000000122361476226660600240710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include "fakedbus/fakedbusservice.h" #include #include DCORE_USE_NAMESPACE class DBusExtendedInterfaceFoo : public DDBusExtendedAbstractInterface { Q_OBJECT public: static inline const char *staticInterfaceName() { return "org.deepin.FakeDBusService"; } explicit DBusExtendedInterfaceFoo(QObject *parent = nullptr) : DDBusExtendedAbstractInterface(FakeDBusService::get_service(), FakeDBusService::get_path(), staticInterfaceName(), QDBusConnection::sessionBus(), parent) { connect(this, &DBusExtendedInterfaceFoo::propertyChanged, this, [this](const QString &propName, const QVariant &value){ if (propName == QStringLiteral("strProperty")) { const QString &strProperty = qvariant_cast(value); if (m_strProp != strProperty) { m_strProp = strProperty; Q_EMIT StrPropertyChanged(m_strProp); } return; } qWarning() << "property not handle: " << propName; return; }); } ~DBusExtendedInterfaceFoo(){ } Q_PROPERTY(QString strProperty READ strProperty WRITE setStrProperty NOTIFY StrPropertyChanged) QString strProperty() { return qvariant_cast(internalPropGet("strProperty", &m_strProp)); } void setStrProperty(const QString &value) { internalPropSet("strProperty", QVariant::fromValue(value), &m_strProp); } Q_SIGNALS: // SIGNALS void StrPropertyChanged(const QString & value) const; private: QString m_strProp; }; class ut_DDBusExtendedAbstractInterface : public testing::Test { public: void SetUp() override { m_fakeService = new FakeDBusService; m_dbusExtend = new DBusExtendedInterfaceFoo; } void TearDown() override { delete m_fakeService; delete m_dbusExtend; } DBusExtendedInterfaceFoo *m_dbusExtend = nullptr; FakeDBusService *m_fakeService = nullptr; }; TEST_F(ut_DDBusExtendedAbstractInterface, sync) { EXPECT_TRUE(m_dbusExtend->sync()); m_dbusExtend->setSync(false, false); EXPECT_FALSE(m_dbusExtend->sync()); } TEST_F(ut_DDBusExtendedAbstractInterface, useCache) { EXPECT_FALSE(m_dbusExtend->useCache()); m_dbusExtend->setUseCache(true); EXPECT_TRUE(m_dbusExtend->useCache()); } TEST_F(ut_DDBusExtendedAbstractInterface, startServiceProcess) { EXPECT_TRUE(m_dbusExtend->isValid()); m_dbusExtend->startServiceProcess(); } TEST_F(ut_DDBusExtendedAbstractInterface, getAllProperties) { QSignalSpy spy(m_dbusExtend, &DDBusExtendedAbstractInterface::asyncGetAllPropertiesFinished); m_dbusExtend->setSync(false); m_dbusExtend->getAllProperties(); EXPECT_TRUE(QTest::qWaitFor([&spy, this]() { return spy.count() >= 1 && !m_dbusExtend->lastExtendedError().isValid(); }, 2000)); } TEST_F(ut_DDBusExtendedAbstractInterface, internalPropGet) { QSignalSpy asyncPropertyFinishedSpy(m_dbusExtend, &DDBusExtendedAbstractInterface::asyncPropertyFinished); QSignalSpy propertyChangedSpy(m_dbusExtend, &DDBusExtendedAbstractInterface::propertyChanged); m_dbusExtend->setSync(false); // internalPropGet m_dbusExtend->strProperty(); QObject::connect(m_dbusExtend, &DDBusExtendedAbstractInterface::propertyChanged, m_dbusExtend, [](const QString &propertyName, const QVariant &value){ if (propertyName == "strProp") EXPECT_EQ(value.toString(), "testDBusService"); qInfo() << "propertyChanged" << propertyName << value; }); EXPECT_TRUE(QTest::qWaitFor([&]() { return asyncPropertyFinishedSpy.count() >= 1 && propertyChangedSpy.count() >= 1 && !m_dbusExtend->lastExtendedError().isValid(); }, 2000)); } TEST_F(ut_DDBusExtendedAbstractInterface, internalPropSet) { QSignalSpy asyncPropertyFinishedSpy(m_dbusExtend, &DDBusExtendedAbstractInterface::asyncSetPropertyFinished); QSignalSpy propertyChangedSpy(m_dbusExtend, &DDBusExtendedAbstractInterface::propertyChanged); m_dbusExtend->setSync(false); // internalPropSet m_dbusExtend->setStrProperty("MyProp"); QObject::connect(m_dbusExtend, &DDBusExtendedAbstractInterface::propertyChanged, m_dbusExtend, [](const QString &propertyName, const QVariant &value){ if (propertyName == "strProp") EXPECT_EQ(value.toString(), "MyProp"); qInfo() << "propertyChanged" << propertyName << value; }); EXPECT_TRUE(QTest::qWaitFor([&]() { return asyncPropertyFinishedSpy.count() >= 1 && propertyChangedSpy.count() >= 1 && !m_dbusExtend->lastExtendedError().isValid(); }, 2000)); } #include "ut_ddbusextendedabstractinterface.moc" dtkcore-5.7.12/tests/ut_ddbusinterface.cpp000066400000000000000000000031301476226660600206150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include "fakedbus/fakedbusservice.h" #include #include using Dtk::Core::DDBusInterface; class ut_DDBusInterface : public testing::Test { public: void SetUp() override { m_testservice = new FakeDBusService(); m_testDBusInterfaceParent = new FakeDBusServiceParent(); // if parent is nullptr m_testInterface = new DDBusInterface(FakeDBusService::get_service(), FakeDBusService::get_path(), FakeDBusService::get_interface(), QDBusConnection::sessionBus()); } void TearDown() override { delete m_testDBusInterfaceParent; delete m_testInterface; delete m_testservice; } DDBusInterface *m_testInterface; FakeDBusService *m_testservice; FakeDBusServiceParent *m_testDBusInterfaceParent; }; TEST_F(ut_DDBusInterface, TestProperty) { auto objectpaths = m_testservice->objectpaths(); EXPECT_EQ(m_testDBusInterfaceParent->objectpaths().length(), objectpaths.length()); auto strproperty = qvariant_cast(m_testInterface->property("strProperty")); EXPECT_EQ(strproperty, m_testservice->strproperty()); } TEST_F(ut_DDBusInterface, suffix) { EXPECT_EQ(m_testInterface->suffix(), ""); m_testInterface->setSuffix("-suffix"); EXPECT_EQ(m_testInterface->suffix(), "-suffix"); } dtkcore-5.7.12/tests/ut_ddbussender.cpp000066400000000000000000000033731476226660600201460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "ddbussender.h" #include #include #include "fakedbus/fakedbusservice.h" using Dtk::Core::DDBusInterface; class ut_DDBusSender : public testing::Test { public: void SetUp() override { m_testservice = new FakeDBusService(); m_sender = new DDBusSender; } void TearDown() override { delete m_testservice; delete m_sender; } FakeDBusService *m_testservice = nullptr; DDBusSender *m_sender = nullptr; }; TEST_F(ut_DDBusSender, DDBusCaller) { QDBusPendingReply reply = m_sender->service(m_testservice->get_service()) .path(m_testservice->get_path()) .interface(m_testservice->get_interface()) .method(QString("foo")) .call(); reply.waitForFinished(); if (reply.error().isValid()) qWarning() << reply.error().message(); ASSERT_TRUE(reply.value() == QString("bar")); } TEST_F(ut_DDBusSender, DDBusProperty) { auto prop = m_sender->service(m_testservice->get_service()) .path(m_testservice->get_path()) .interface(m_testservice->get_interface()) .property(QString("strProperty")); QDBusPendingReply reply = prop.get(); reply.waitForFinished(); if (reply.error().isValid()) qWarning() << reply.error().message(); ASSERT_TRUE(reply.value().toString() == QString("testDBusService")); auto res = prop.set("myProp"); res.waitForFinished(); if (res.error().isValid()) qWarning() << res.error().message(); ASSERT_TRUE(m_testservice->strproperty() == QString("myProp")); } dtkcore-5.7.12/tests/ut_ddci.cpp000066400000000000000000000447711476226660600165560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include DCORE_USE_NAMESPACE class ut_DCI : public testing::Test { public: void SetUp() override { QLoggingCategory::setFilterRules("dtk.dci.file.debug=true\n" "dtk.dci.fileengine.debug=true"); } }; TEST_F(ut_DCI, DDciFile) { { // 空文件 DDciFile dciFile; ASSERT_TRUE(dciFile.isValid()); ASSERT_TRUE(dciFile.exists("/")); ASSERT_EQ(dciFile.list("/").count(), 0); ASSERT_EQ(dciFile.toData(), QByteArrayLiteral("DCI\0\1\0\0\0")); } { // 最小数据文件 DDciFile dciFile(QByteArrayLiteral("DCI\0\1\0\0\0")); ASSERT_TRUE(dciFile.isValid()); ASSERT_TRUE(dciFile.exists("/")); ASSERT_EQ(dciFile.list("/").count(), 0); ASSERT_EQ(dciFile.toData(), QByteArrayLiteral("DCI\0\1\0\0\0")); } { // 错误的版本 DDciFile dciFile(QByteArrayLiteral("DCI\0\0\0\0\0")); ASSERT_FALSE(dciFile.isValid()); } { // 错误的文件数量 DDciFile dciFile(QByteArrayLiteral("DCI\0\1\255\255\255")); ASSERT_FALSE(dciFile.isValid()); } { // 创建目录 DDciFile dciFile; ASSERT_TRUE(dciFile.mkdir("/test")); ASSERT_TRUE(dciFile.exists("/test")); ASSERT_EQ(dciFile.list("/"), QStringList{"/test"}); ASSERT_EQ(dciFile.childrenCount("/"), 1); } { // 创建目录 DDciFile dciFile; ASSERT_TRUE(dciFile.mkdir("/test")); ASSERT_TRUE(dciFile.exists("/test")); ASSERT_EQ(dciFile.list("/"), QStringList{"/test"}); ASSERT_EQ(dciFile.type("/test"), DDciFile::Directory); ASSERT_EQ(dciFile.childrenCount("/"), 1); // 创建文件 ASSERT_TRUE(dciFile.writeFile("/test/test.txt", "test\n")); ASSERT_TRUE(dciFile.exists("/test/test.txt")); ASSERT_EQ(dciFile.list("/test"), QStringList{"/test/test.txt"}); ASSERT_EQ(dciFile.childrenCount("/test"), 1); ASSERT_EQ(dciFile.type("/test/test.txt"), DDciFile::File); ASSERT_EQ(dciFile.dataRef("/test/test.txt"), QByteArray("test\n")); // 软链接 // 链接一个不存在的文件 ASSERT_TRUE(dciFile.link("/no", "/1.link")); ASSERT_TRUE(dciFile.exists("/1.link")); ASSERT_EQ(dciFile.type("/1.link"), DDciFile::Symlink); ASSERT_EQ(dciFile.symlinkTarget("/1.link"), "/no"); ASSERT_EQ(dciFile.symlinkTarget("/1.link", true), "/no"); // 当链接目标无效时,无论如何都不允许写入数据 ASSERT_FALSE(dciFile.writeFile("/1.link", "", false)); ASSERT_FALSE(dciFile.writeFile("/1.link", "", true)); // 链接一个目录 ASSERT_TRUE(dciFile.link("/test", "/2.link")); ASSERT_TRUE(dciFile.symlinkTarget("/2.link").isEmpty()); ASSERT_FALSE(dciFile.mkdir("/2.link/test")); // 链接一个存在的文件 ASSERT_TRUE(dciFile.link("/test/test.txt", "/3.link")); ASSERT_EQ(dciFile.symlinkTarget("/3.link"), "/test/test.txt"); ASSERT_EQ(dciFile.dataRef("/3.link"), QByteArray("test\n")); ASSERT_TRUE(dciFile.writeFile("/3.link", "TEST", true)); ASSERT_EQ(dciFile.dataRef("/test/test.txt"), QByteArray("TEST")); // 相对路径链接 ASSERT_TRUE(dciFile.link("./test/test.txt", "/4.link")); ASSERT_EQ(dciFile.symlinkTarget("/4.link"), "/test/test.txt"); ASSERT_EQ(dciFile.symlinkTarget("/4.link", true), "./test/test.txt"); ASSERT_EQ(dciFile.dataRef("/4.link"), QByteArray("TEST")); // 链接一个软链接,测试 ".." 类型的相对路径 ASSERT_TRUE(dciFile.link("../4.link", "/test/5.link")); ASSERT_EQ(dciFile.symlinkTarget("/test/5.link"), "/4.link"); ASSERT_EQ(dciFile.symlinkTarget("/test/5.link", true), "../4.link"); ASSERT_EQ(dciFile.dataRef("/test/5.link"), QByteArray("TEST")); ASSERT_TRUE(dciFile.writeFile("/test/5.link", "test\n", true)); ASSERT_EQ(dciFile.dataRef("/test/test.txt"), QByteArray("test\n")); // 链接同目录文件 ASSERT_TRUE(dciFile.link("test.txt", "/test/6.link")); ASSERT_EQ(dciFile.dataRef("/test/6.link"), QByteArray("test\n")); // 链接对象删除 ASSERT_TRUE(dciFile.remove("/4.link")); ASSERT_TRUE(dciFile.exists("/test/5.link")); ASSERT_EQ(dciFile.symlinkTarget("/test/5.link"), "/4.link"); ASSERT_TRUE(dciFile.dataRef("/test/5.link").isEmpty()); ASSERT_FALSE(dciFile.writeFile("/test/5.link", "", true)); // 链接对象改名 ASSERT_TRUE(dciFile.rename("/test/6.link", "/test/7.link")); ASSERT_EQ(dciFile.dataRef("/test/7.link"), QByteArray("test\n")); // 链接对象更换目录 ASSERT_TRUE(dciFile.rename("/test/7.link", "/7.link")); ASSERT_EQ(dciFile.symlinkTarget("/7.link"), "/test.txt"); ASSERT_TRUE(dciFile.dataRef("/7.link").isEmpty()); { // 复制数据 DDciFile dciFile2(dciFile.toData()); ASSERT_TRUE(dciFile2.isValid()); ASSERT_EQ(dciFile2.list("/"), dciFile.list("/")); ASSERT_EQ(dciFile2.list("/test"), dciFile.list("/test")); ASSERT_EQ(dciFile2.dataRef("/test/test.txt"), QByteArray("test\n")); ASSERT_EQ(dciFile2.dataRef("/test/3.link"), dciFile2.dataRef("/test/text.txt")); ASSERT_EQ(dciFile.toData(), dciFile2.toData()); } // 清理链接文件 for (const QString &file : dciFile.list("/", false)) { if (dciFile.type(file) == DDciFile::Symlink) dciFile.remove(file); } for (const QString &file : dciFile.list("/test", false)) { if (dciFile.type(file) == DDciFile::Symlink) dciFile.remove(file); } // 改写文件数据 ASSERT_FALSE(dciFile.writeFile("/test/test.txt", "override the\"test.txt\"")); ASSERT_TRUE(dciFile.writeFile("/test/test.txt", "override the\"test.txt\"", true)); ASSERT_EQ(dciFile.dataRef("/test/test.txt"), "override the\"test.txt\""); // 文件删除 ASSERT_TRUE(dciFile.remove("/test/test.txt")); ASSERT_FALSE(dciFile.exists("/test/test.txt")); ASSERT_EQ(dciFile.list("/test"), QStringList{}); // 目录删除 ASSERT_TRUE(dciFile.writeFile("/test/test.txt", "")); ASSERT_TRUE(dciFile.remove("/test")); ASSERT_FALSE(dciFile.exists("/test")); ASSERT_EQ(dciFile.list("/"), QStringList{}); ASSERT_EQ(dciFile.toData(), QByteArrayLiteral("DCI\0\1\0\0\0")); } { DDciFile dciFile; ASSERT_TRUE(dciFile.mkdir("/test")); ASSERT_TRUE(dciFile.writeFile("/test.txt", "")); // 重命名 ASSERT_TRUE(dciFile.rename("/test.txt", "/test/new_test.txt")); ASSERT_TRUE(dciFile.exists("/test/new_test.txt")); ASSERT_FALSE(dciFile.rename("/test.txt", "/test/new_test.txt")); ASSERT_EQ(dciFile.list("/test", true), QStringList{"new_test.txt"}); ASSERT_EQ(dciFile.list("/test"), QStringList{"/test/new_test.txt"}); // override 重命名 ASSERT_TRUE(dciFile.writeFile("/test.txt", "test", false)); ASSERT_FALSE(dciFile.rename("/test.txt", "/test/new_test.txt", false)); ASSERT_TRUE(dciFile.rename("/test.txt", "/test/new_test.txt", true)); ASSERT_EQ(dciFile.dataRef("/test/new_test.txt"), "test"); // 文件清空 ASSERT_TRUE(dciFile.remove("/")); ASSERT_EQ(dciFile.list("/"), QStringList{}); ASSERT_EQ(dciFile.childrenCount("/"), 0); ASSERT_EQ(dciFile.toData(), QByteArrayLiteral("DCI\0\1\0\0\0")); } // DDciFile::copy { DDciFile dciFile; // 文件复制 ASSERT_TRUE(dciFile.writeFile("/test.txt", "test")); ASSERT_TRUE(dciFile.copy("/test.txt", "/test.txt.new")); ASSERT_TRUE(dciFile.exists("/test.txt.new")); ASSERT_EQ(dciFile.list("/", true), (QStringList{"test.txt", "test.txt.new"})); ASSERT_EQ(dciFile.dataRef("/test.txt"), dciFile.dataRef("/test.txt.new")); // 目录复制 ASSERT_TRUE(dciFile.mkdir("/test")); ASSERT_TRUE(dciFile.rename("/test.txt", "/test/test.txt")); ASSERT_TRUE(dciFile.copy("/test", "/test.new")); ASSERT_TRUE(dciFile.exists("/test.new/test.txt")); ASSERT_EQ(dciFile.list("/test.new", true), (QStringList{"test.txt"})); ASSERT_EQ(dciFile.dataRef("/test/test.txt"), dciFile.dataRef("/test.new/test.txt")); } // 文件排序 { DDciFile dciFile; dciFile.mkdir("/b01"); dciFile.writeFile("/a2.txt", ""); dciFile.writeFile("/b2", ""); dciFile.writeFile("/a11.txt", ""); const auto &list = dciFile.list("/", true); ASSERT_EQ(list, (QStringList{"a2.txt", "a11.txt", "b01", "b2"})); dciFile.writeFile("/b01/222", ""); dciFile.link("/b01/33", "/b01/1111"); dciFile.writeFile("/b01/33", ""); ASSERT_EQ(dciFile.list("/b01", true), (QStringList{"33", "222", "1111"})); ASSERT_TRUE(dciFile.rename("/a11.txt", "/b01/200")); ASSERT_TRUE(dciFile.copy("/a2.txt", "/b01/200.txt")); ASSERT_EQ(dciFile.list("/", true), (QStringList{"a2.txt", "b01", "b2"})); ASSERT_EQ(dciFile.list("/b01", true), (QStringList{"33", "200", "200.txt", "222", "1111"})); } } class TestDCIFileHelper { public: TestDCIFileHelper(const QString &fileName) : fileName(fileName) { if (QFile::exists(fileName)) QFile::remove(fileName); } ~TestDCIFileHelper() { QFile::remove(fileName); } inline QString dciFormatFilePath(const QString &subfile = QString()) const { return "dci:" + fileName + subfile; } inline QString sourceFileName() const { return fileName; } private: QString fileName; }; static QByteArray readAll(const QString &file) { QFile f(file); if (!f.open(QIODevice::ReadOnly)) return {}; return f.readAll(); } TEST_F(ut_DCI, DFileEngine) { DDciFile::registerFileEngine(); { TestDCIFileHelper helper(QDir::temp().absoluteFilePath("test.dci")); // 空 dci 文件创建 QFile file(helper.dciFormatFilePath()); ASSERT_TRUE(file.exists()); QFileInfo info(file); ASSERT_TRUE(info.isDir()); ASSERT_TRUE(info.isRoot()); // 文件夹不可写入 ASSERT_FALSE(file.open(QIODevice::WriteOnly)); // 空文件遍历 QDir dir(info.absoluteFilePath()); ASSERT_EQ(dir.entryList(), QStringList{}); } { TestDCIFileHelper helper(QDir::temp().absoluteFilePath("test.dci")); { // 内部文件创建 QFile file(helper.dciFormatFilePath("/test.txt")); ASSERT_FALSE(file.open(QIODevice::ReadOnly)); ASSERT_TRUE(file.open(QIODevice::ReadOnly | QIODevice::WriteOnly)); ASSERT_TRUE(file.exists()); ASSERT_TRUE(QFileInfo(file).isFile()); ASSERT_TRUE(file.write("Hello") == 5); ASSERT_TRUE(file.seek(0)); ASSERT_EQ(file.readAll(), "Hello"); ASSERT_TRUE(file.flush()); // 链接文件创建,绝对路径链接 ASSERT_TRUE(file.link(helper.dciFormatFilePath("/test.txt.link"))); { QFile linkFile(helper.dciFormatFilePath("/test.txt.link")); ASSERT_TRUE(QFileInfo(linkFile).isSymLink()); ASSERT_EQ(linkFile.symLinkTarget(), "/test.txt"); ASSERT_TRUE(linkFile.open(QIODevice::ReadOnly)); ASSERT_EQ(linkFile.readAll(), "Hello"); ASSERT_EQ(linkFile.size(), file.size()); } file.close(); // 文件信息 QFileInfo info1(file); QFileInfo info2(helper.sourceFileName()); ASSERT_FALSE(info1.isRoot()); ASSERT_EQ(info1.permissions(), info2.permissions()); ASSERT_EQ(info1.fileTime(QFile::FileAccessTime), info2.fileTime(QFile::FileAccessTime)); ASSERT_EQ(info1.fileTime(QFile::FileBirthTime), info2.fileTime(QFile::FileBirthTime)); ASSERT_EQ(info1.fileTime(QFile::FileMetadataChangeTime), info2.fileTime(QFile::FileMetadataChangeTime)); ASSERT_EQ(info1.fileTime(QFile::FileModificationTime), info2.fileTime(QFile::FileModificationTime)); ASSERT_EQ(info1.ownerId(), info2.ownerId()); ASSERT_EQ(info1.owner(), info2.owner()); ASSERT_EQ(info1.groupId(), info2.groupId()); ASSERT_EQ(info1.group(), info2.group()); // 目录遍历 QDir dir(helper.dciFormatFilePath()); ASSERT_EQ(dir.entryList(), (QStringList{"test.txt", "test.txt.link"})); // 文件大小 ASSERT_EQ(file.size(), 5); ASSERT_TRUE(file.resize(10)); ASSERT_EQ(file.size(), 10); ASSERT_EQ(QFile(helper.dciFormatFilePath("/test.txt.link")).size(), 10); } { // 文件读取 QFile file(helper.dciFormatFilePath("/test.txt")); ASSERT_TRUE(file.exists()); ASSERT_TRUE(file.open(QIODevice::ReadOnly)); ASSERT_EQ(file.readAll(), QByteArrayLiteral("Hello\0\0\0\0\0")); file.close(); // [/test.txt, /test.txt.link] } { // 文件内容改写 QFile file(helper.dciFormatFilePath("/test.txt")); ASSERT_TRUE(file.open(QIODevice::ReadWrite)); ASSERT_TRUE(file.seek(1)); ASSERT_TRUE(file.putChar('E')); char ch; ASSERT_TRUE(file.getChar(&ch)); ASSERT_EQ(ch, 'l'); ASSERT_EQ(file.readAll(), QByteArrayLiteral("lo\0\0\0\0\0")); ASSERT_TRUE(file.seek(0)); ASSERT_EQ(file.readAll(), QByteArrayLiteral("HEllo\0\0\0\0\0")); ASSERT_EQ(readAll(helper.dciFormatFilePath("/test.txt.link")), QByteArrayLiteral("HEllo\0\0\0\0\0")); } // 目录创建 ASSERT_TRUE(QDir(helper.dciFormatFilePath()).mkdir("1")); ASSERT_FALSE(QDir(helper.dciFormatFilePath()).mkdir("2/3")); ASSERT_TRUE(QDir(helper.dciFormatFilePath()).mkpath("2/3")); ASSERT_TRUE(QFileInfo(helper.dciFormatFilePath("/1")).isDir()); // [/test.txt, /test.txt.link, /1, /2, /2/3] // 目录 rename ASSERT_FALSE(QFile::rename(helper.dciFormatFilePath("/1"), "/1")); ASSERT_TRUE(QFile::rename(helper.dciFormatFilePath("/1"), helper.dciFormatFilePath("/1.new"))); ASSERT_TRUE(QFile::rename(helper.dciFormatFilePath("/2"), helper.dciFormatFilePath("/2.new"))); ASSERT_TRUE(QFile::rename(helper.dciFormatFilePath("/2.new/3"), helper.dciFormatFilePath("/3"))); // [/test.txt, /test.txt.link, /1.new, /2.new, /3] // 文件 rename ASSERT_TRUE(QFile::rename(helper.dciFormatFilePath("/test.txt"), helper.dciFormatFilePath("/test.txt.new"))); ASSERT_TRUE(QFile::rename(helper.dciFormatFilePath("/test.txt.new"), helper.dciFormatFilePath("/1.new/test.txt"))); // [/1.new, /1.new/test.txt.new, /test.txt.link, /2.new, /3] // 此时的 link file 应该无效 ASSERT_TRUE(readAll(helper.dciFormatFilePath("/test.txt.link")).isEmpty()); // 链接文件 rename ASSERT_TRUE(QFile::rename(helper.dciFormatFilePath("/test.txt.link"), helper.dciFormatFilePath("/1.new/test.txt.link"))); // 复制 ASSERT_TRUE(QFile::copy(helper.dciFormatFilePath("/1.new/test.txt"), helper.dciFormatFilePath("/test.txt"))); // 链接文件复制 ASSERT_TRUE(QFile::copy(helper.dciFormatFilePath("/1.new/test.txt.link"), helper.dciFormatFilePath("/test.txt.link"))); // 检查复制/rename后的链接文件 ASSERT_EQ(QFile(helper.dciFormatFilePath("/test.txt.link")).symLinkTarget(), QStringLiteral("/test.txt")); ASSERT_EQ(readAll(helper.dciFormatFilePath("/test.txt.link")), readAll(helper.dciFormatFilePath("/test.txt"))); ASSERT_EQ(QFile(helper.dciFormatFilePath("/1.new/test.txt.link")).symLinkTarget(), QStringLiteral("/test.txt")); ASSERT_EQ(readAll(helper.dciFormatFilePath("/1.new/test.txt.link")), readAll(helper.dciFormatFilePath("/test.txt"))); // 复制目录 ASSERT_TRUE(QFile::copy(helper.dciFormatFilePath("/1.new"), helper.dciFormatFilePath("/1"))); ASSERT_EQ(QDir(helper.dciFormatFilePath("/1")).entryList(), QDir(helper.dciFormatFilePath("/1.new")).entryList()); // [/1.new, /1.new/test.txt, /1.new/test.txt.link, /2.new, /3, /test.txt, /test.txt.link, /1] // 目录遍历 QStringList list { helper.dciFormatFilePath("/1"), helper.dciFormatFilePath("/1/test.txt.link"), helper.dciFormatFilePath("/1/test.txt"), helper.dciFormatFilePath("/1.new"), helper.dciFormatFilePath("/1.new/test.txt"), helper.dciFormatFilePath("/1.new/test.txt.link"), helper.dciFormatFilePath("/2.new"), helper.dciFormatFilePath("/3"), helper.dciFormatFilePath("/test.txt"), helper.dciFormatFilePath("/test.txt.link") }; QDirIterator di(helper.dciFormatFilePath(), QDirIterator::Subdirectories); while (di.hasNext()) { const QString &file = di.next(); ASSERT_TRUE(list.removeOne(file)); } ASSERT_TRUE(list.isEmpty()); // 删除 ASSERT_TRUE(QFile::remove(helper.dciFormatFilePath("/test.txt"))); ASSERT_TRUE(QFile::remove(helper.dciFormatFilePath("/test.txt.link"))); ASSERT_TRUE(QFile::remove(helper.dciFormatFilePath("/2.new"))); ASSERT_TRUE(QFile::remove(helper.dciFormatFilePath("/1.new"))); // [/3] ASSERT_EQ(QDir(helper.dciFormatFilePath()).entryList(), (QStringList {"1", "3"})); } } dtkcore-5.7.12/tests/ut_ddesktopentrytest.cpp000066400000000000000000000074071476226660600214450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include DCORE_USE_NAMESPACE const QString testFileContent = { QStringLiteral(R"desktop(# A. Example Desktop Entry File [Desktop Entry] Version=1.0 Type=Application Name=Foo Viewer Name[zh_CN]=福查看器 Comment=The best viewer for Foo objects available! # Next line have an extra " character Comment[zh_CN]=最棒的 "福 查看器! TryExec=fooview Exec=fooview %F Icon=fooview MimeType=image/x-foo; Actions=Gallery;Create; [Desktop Action Gallery] Exec=fooview --gallery Name=Browse Gallery [Desktop Action Create] Exec=fooview --create-new Name=Create a new Foo! Icon=fooview-new )desktop") }; class ut_DesktopEntry : public testing::Test { public: static void SetUpTestCase() { //qDebug() << "*****************" << __FUNCTION__; } static void TearDownTestCase() { //qDebug() << "*****************" << __FUNCTION__; } virtual void SetUp(); virtual void TearDown(); }; void ut_DesktopEntry::SetUp() { } void ut_DesktopEntry::TearDown() { } TEST_F(ut_DesktopEntry, ParseFile) { QTemporaryFile file("testReadXXXXXX.desktop"); ASSERT_TRUE(file.open()); const QString fileName = file.fileName(); QTextStream ts(&file); ts << testFileContent; file.close(); ASSERT_TRUE(QFile::exists(fileName)); QScopedPointer desktopFile(new DDesktopEntry(fileName)); QStringList allGroups = desktopFile->allGroups(); ASSERT_EQ(allGroups.count(), 3); ASSERT_TRUE(allGroups.contains("Desktop Entry") && allGroups.contains("Desktop Action Gallery") && allGroups.contains("Desktop Action Create")); ASSERT_EQ(desktopFile->allGroups(true)[0], QStringLiteral("Desktop Entry")); ASSERT_EQ(desktopFile->localizedValue("Name", "zh_CN"), QStringLiteral("福查看器")); ASSERT_EQ(desktopFile->localizedValue("Name", "empty"), QStringLiteral("Foo Viewer")); ASSERT_EQ(desktopFile->keys("Desktop Entry"), QStringList({"Actions", "Comment", "Comment[zh_CN]", "Exec", "Icon", "MimeType", "Name", "Name[zh_CN]", "TryExec", "Type", "Version"})); { struct RestoreLocale { ~RestoreLocale() { QLocale::setDefault(QLocale::system()); } } restoreLocale; Q_UNUSED(restoreLocale); QLocale::setDefault(QLocale("zh_CN")); ASSERT_EQ(desktopFile->localizedValue("Name"), QStringLiteral("福查看器")); QLocale::setDefault(QLocale::c()); ASSERT_EQ(desktopFile->localizedValue("Name"), QStringLiteral("Foo Viewer")); } ASSERT_EQ(desktopFile->stringValue("Name"), QStringLiteral("Foo Viewer")); ASSERT_EQ(desktopFile->setRawValue("Bar Viewer", "Name"), true); ASSERT_EQ(desktopFile->stringValue("Name"), QStringLiteral("Bar Viewer")); ASSERT_EQ(desktopFile->setLocalizedValue("霸查看器", "zh_CN", "Name"), true); ASSERT_EQ(desktopFile->localizedValue("Name", "zh_CN"), QStringLiteral("霸查看器")); ASSERT_EQ(desktopFile->contains("Semicolon"), false); ASSERT_EQ(desktopFile->setRawValue(";grp\\;2;grp3;", "Semicolon"), true); ASSERT_EQ(desktopFile->stringListValue("Semicolon"), QStringList({"", "grp;2", "grp3"})); ASSERT_EQ(desktopFile->contains("Semicolon"), true); ASSERT_EQ(desktopFile->removeEntry("Semicolon"), true); ASSERT_EQ(desktopFile->contains("Semicolon"), false); //qDebug() << desktopFile->save(); //qDebug() << fileName; } TEST_F(ut_DesktopEntry, escape) { QString slash("\\\\"); ASSERT_TRUE(DDesktopEntry::escapeExec(slash) == slash); ASSERT_TRUE(DDesktopEntry::unescapeExec(slash) == slash); } dtkcore-5.7.12/tests/ut_ddisksizeformatter.cpp000066400000000000000000000041231476226660600215530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "util/ddisksizeformatter.h" DCORE_USE_NAMESPACE class ut_DDiskSizeFormatter : public testing::Test { protected: void SetUp() override; void TearDown() override; DDiskSizeFormatter diskSizeFormatter; }; void ut_DDiskSizeFormatter::SetUp() { } void ut_DDiskSizeFormatter::TearDown() { } TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterFormatAs) { diskSizeFormatter.rate(1024); qreal result0 = diskSizeFormatter.formatAs(2048, DDiskSizeFormatter::B, DDiskSizeFormatter::K); ASSERT_TRUE(qFuzzyCompare(result0, 2)); qreal result1 = diskSizeFormatter.formatAs(2, DDiskSizeFormatter::K, DDiskSizeFormatter::B); ASSERT_TRUE(qFuzzyCompare(result1, 2048)); qreal result2 = diskSizeFormatter.formatAs(2, DDiskSizeFormatter::K, DDiskSizeFormatter::K); ASSERT_TRUE(qFuzzyCompare(result2, 2)); } TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterFormat) { diskSizeFormatter.rate(1024); QPair result = diskSizeFormatter.format(2048, DDiskSizeFormatter::B); ASSERT_TRUE(qFuzzyCompare(result.first, 2)); ASSERT_EQ(result.second, DDiskSizeFormatter::K); } TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterFormatAsUnitList) { diskSizeFormatter.rate(1024); QList> result = diskSizeFormatter.formatAsUnitList(2049, DDiskSizeFormatter::K); ASSERT_TRUE(qFuzzyCompare(result[0].first, 2)); ASSERT_EQ(result[0].second, DDiskSizeFormatter::M); ASSERT_TRUE(qFuzzyCompare(result[1].first, 1)); ASSERT_EQ(result[1].second, DDiskSizeFormatter::K); } TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterUnitStr) { ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::B), "B"); ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::K), "KB"); ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::M), "MB"); ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::G), "GB"); ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::T), "TB"); } dtkcore-5.7.12/tests/ut_dexpected.cpp000066400000000000000000000025571476226660600176140ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "dexpected.h" DCORE_USE_NAMESPACE TEST(ut_DExpected, unexpected) { DExpected exp_void { DUnexpected { emplace_tag::USE_EMPLACE, 404, "Not Found"} }; EXPECT_FALSE(exp_void.hasValue()); EXPECT_EQ(exp_void.error().getErrorCode(), 404); EXPECT_EQ(exp_void.error().getErrorMessage(), "Not Found"); } TEST(ut_DExpected, expected) { DExpected exp_void {}; EXPECT_TRUE(exp_void.hasValue()); // void DExpected exp_int {200}; EXPECT_TRUE(exp_int.hasValue()); EXPECT_EQ(exp_int.value(), 200); } TEST(ut_DError, defaultError) { DError error; EXPECT_EQ(error.getErrorCode(), -1); EXPECT_EQ(error.getErrorMessage(), QString()); } TEST(ut_DError, setError) { DError error(404, "Not Found"); EXPECT_EQ(error.getErrorCode(), 404); EXPECT_EQ(error.getErrorMessage(), "Not Found"); error.setErrorCode(502); error.setErrorMessage("Bad Gateway"); EXPECT_EQ(error.getErrorCode(), 502); EXPECT_EQ(error.getErrorMessage(), "Bad Gateway"); } TEST(ut_DError, operator) { DError error(404, "Not Found"); DError copy = error; EXPECT_EQ(copy, error); copy.setErrorCode(502); EXPECT_NE(copy, error); qDebug() << error; // operator << } dtkcore-5.7.12/tests/ut_dexportedinterface.cpp000066400000000000000000000053211476226660600215160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include DCORE_USE_NAMESPACE class ut_DExportedInterface : public testing::Test { public: static void SetUpTestSuite() { QDBusConnection::sessionBus().registerService("org.deepin.ExpIntfTest"); _infc = new DUtil::DExportedInterface; _infc->registerAction("quit", "quit the application", [](QString)->QVariant { qDebug() << "quit? No Way!"; return QVariant(); }); _infc->registerAction("answer", "answer to the ultimate question of life, the universe, and everything", [](QString)->QVariant { return QVariant(42); }); } static void TearDownTestSuite() { QDBusConnection::sessionBus().unregisterService("org.deepin.ExpIntfTest"); delete _infc; } static DUtil::DExportedInterface *_infc; }; DUtil::DExportedInterface *ut_DExportedInterface::_infc = nullptr; TEST_F(ut_DExportedInterface, list) { auto caller = DDBusSender().service("org.deepin.ExpIntfTest") .path("/") .interface("com.deepin.ExportedInterface") .method("list"); auto msg = caller.call(); msg.waitForFinished(); QDBusReply reply = msg; EXPECT_EQ(reply.value().size(), 2); } TEST_F(ut_DExportedInterface, help) { auto caller = DDBusSender().service("org.deepin.ExpIntfTest") .path("/") .interface("com.deepin.ExportedInterface") .method("help") .arg(QString("quit")); auto msg = caller.call(); msg.waitForFinished(); QDBusReply reply = msg; EXPECT_EQ(reply.value(), "quit: quit the application"); } TEST_F(ut_DExportedInterface, invoke) { auto caller = DDBusSender().service("org.deepin.ExpIntfTest") .path("/") .interface("com.deepin.ExportedInterface") .method("invoke") .arg(QString("answer")) .arg(QString("balabala")); auto msg = caller.call(); msg.waitForFinished(); QDBusReply reply = msg; EXPECT_EQ(reply.value(), 42); caller = DDBusSender().service("org.deepin.ExpIntfTest") .path("/") .interface("com.deepin.ExportedInterface") .method("invoke") .arg(QString("unkownAction")) // invoke an unregistered action .arg(QString("balabala")); msg = caller.call(); msg.waitForFinished(); EXPECT_TRUE(msg.isError()); EXPECT_TRUE(msg.error().type() == QDBusError::ErrorType::InvalidArgs); } dtkcore-5.7.12/tests/ut_dfilesystemwatcher.cpp000066400000000000000000000053331476226660600215500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) #include //Avoid changing the access control of the standard library #endif #define private public #include "filesystem/dfilesystemwatcher.h" #undef private DCORE_USE_NAMESPACE class ut_DFileSystemWatcher : public testing::Test { protected: void SetUp() override; void TearDown() override; DFileSystemWatcher *fileSystemWatcher = nullptr; }; void ut_DFileSystemWatcher::SetUp() { fileSystemWatcher = new DFileSystemWatcher(nullptr); QDir dir0("/tmp/etc0/"); if (!dir0.exists()) dir0.mkdir("/tmp/etc0/"); QDir dir1("/tmp/etc1/"); if (!dir1.exists()) dir1.mkdir("/tmp/etc1/"); } void ut_DFileSystemWatcher::TearDown() { if (fileSystemWatcher) { delete fileSystemWatcher; fileSystemWatcher = nullptr; } QDir dir0("/tmp/etc0/"); if (dir0.exists()) dir0.remove("/tmp/etc0/"); QDir dir1("/tmp/etc1/"); if (dir1.exists()) dir1.remove("/tmp/etc1/"); } TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherAddPath) { if (!fileSystemWatcher->d_func()) return; fileSystemWatcher->addPath("/tmp/etc0"); QStringList dirs = fileSystemWatcher->directories(); ASSERT_TRUE(dirs.contains("/tmp/etc0")); } TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherAddPaths) { if (!fileSystemWatcher->d_func()) return; fileSystemWatcher->addPaths( QStringList() << "/tmp/etc0" << "/tmp/etc1"); QStringList dirs = fileSystemWatcher->directories(); ASSERT_TRUE(dirs.contains("/tmp/etc0")); ASSERT_TRUE(dirs.contains("/tmp/etc1")); } TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherRemovePath) { if (!fileSystemWatcher->d_func()) return; fileSystemWatcher->addPath("/tmp/etc0"); QStringList dirs0 = fileSystemWatcher->directories(); ASSERT_TRUE(dirs0.contains("/tmp/etc0")); fileSystemWatcher->removePath("/tmp/etc0"); QStringList dirs1 = fileSystemWatcher->directories(); ASSERT_FALSE(dirs1.contains("/tmp/etc0")); } TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherRemovePaths) { if (!fileSystemWatcher->d_func()) return; fileSystemWatcher->addPaths( QStringList() << "/tmp/etc0" << "/tmp/etc1"); QStringList dirs0 = fileSystemWatcher->directories(); ASSERT_TRUE(dirs0.contains("/tmp/etc0")); ASSERT_TRUE(dirs0.contains("/tmp/etc1")); fileSystemWatcher->removePaths(QStringList() << "/tmp/etc0" << "/tmp/etc1"); QStringList dirs1 = fileSystemWatcher->directories(); ASSERT_FALSE(dirs1.contains("/tmp/etc0")); ASSERT_FALSE(dirs1.contains("/tmp/etc1")); } dtkcore-5.7.12/tests/ut_dfilewatcher.cpp000066400000000000000000000115251476226660600203030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "filesystem/dfilewatcher.h" DCORE_USE_NAMESPACE class ut_DFileWatcher : public testing::Test { protected: void SetUp() override; void TearDown() override; DFileWatcher *fileWatcher = nullptr; }; void ut_DFileWatcher::SetUp() { QDir dir("/tmp/etc/"); if (!dir.exists()) dir.mkdir("/tmp/etc/"); QFile file("/tmp/etc/test"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; file.close(); fileWatcher = new DFileWatcher("/tmp/etc/test"); } void ut_DFileWatcher::TearDown() { if (fileWatcher) { delete fileWatcher; fileWatcher = nullptr; } QDir dir("/tmp/etc/"); if (dir.exists()) dir.remove("/tmp/etc/"); QFile file("/tmp/etc/test"); if (file.exists()) file.remove(); QFile file1("/tmp/etc/test1"); if (file1.exists()) file1.remove(); } TEST_F(ut_DFileWatcher, testDFileWatcherFileUrl) { QUrl url = fileWatcher->fileUrl(); ASSERT_TRUE(url.toString() == "file:///tmp/etc/test"); } TEST_F(ut_DFileWatcher, testDFileWatcherStartWatcher) { if (!fileWatcher->startWatcher()) return; fileWatcher->setEnabledSubfileWatcher(QUrl()); ASSERT_TRUE(fileWatcher->startWatcher()); } TEST_F(ut_DFileWatcher, testDFileWatcherStopWatcher) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); ASSERT_TRUE(fileWatcher->stopWatcher()); } TEST_F(ut_DFileWatcher, testDFileWatcherRestartWatcher) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); ASSERT_TRUE(fileWatcher->restartWatcher()); } TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileDeleted) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileDeleted); QFile file("/tmp/etc/test"); if (file.exists()) file.remove(); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); } TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileAttributeChanged) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileAttributeChanged); QFile file("/tmp/etc/test"); if (file.exists()) { file.remove(); } if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; file.close(); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); } TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileMoved) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileMoved); #else QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileDeleted); #endif QString oldFile("/tmp/etc/test"); QString newFile("/tmp/etc/test1"); QFile::rename(oldFile, newFile); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); } TEST_F(ut_DFileWatcher, testDFileSystemWatcherSubfileCreated) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); QSignalSpy spy(fileWatcher, &DBaseFileWatcher::subfileCreated); QFile file("/tmp/etc/test"); if (file.exists()) { file.remove(); } if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); } TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileModified) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileModified); QFile file("/tmp/etc/test"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } QTextStream out(&file); out << "hello"; file.close(); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); } TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileClosed) { if (!fileWatcher->startWatcher()) return; ASSERT_TRUE(fileWatcher->startWatcher()); QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileClosed); QFile file("/tmp/etc/test"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } file.close(); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); } dtkcore-5.7.12/tests/ut_dfilewatchermanager.cpp000066400000000000000000000040541476226660600216350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include "filesystem/dfilewatcher.h" #include "filesystem/dfilewatchermanager.h" DCORE_USE_NAMESPACE class ut_DFileWatcherManager : public testing::Test { protected: void SetUp() override; void TearDown() override; DFileWatcherManager *fileWatcherManager = nullptr; }; void ut_DFileWatcherManager::SetUp() { fileWatcherManager = new DFileWatcherManager(nullptr); } void ut_DFileWatcherManager::TearDown() { if (fileWatcherManager) { delete fileWatcherManager; fileWatcherManager = nullptr; } } TEST_F(ut_DFileWatcherManager, testDFileWatcherManagerAdd) { QTemporaryFile tmpfile; if (!tmpfile.open()) return; auto watcher = fileWatcherManager->add(tmpfile.fileName()); if (!watcher->startWatcher()) return; // test fileDeleted signal QSignalSpy spy(watcher, &DBaseFileWatcher::fileDeleted); if (tmpfile.exists()) tmpfile.remove(); ASSERT_TRUE(QTest::qWaitFor([&spy]() { return spy.count() >= 1; }, 1000)); ASSERT_TRUE(spy.count() >= 1); watcher->stopWatcher(); } TEST_F(ut_DFileWatcherManager, testDFileWatcherManagerRemove) { fileWatcherManager->add("/tmp/test"); fileWatcherManager->remove("/tmp/test"); ASSERT_EQ(fileWatcherManager->watchedFiles().count(), 0); } TEST_F(ut_DFileWatcherManager, testDFileWatcherManagerRemoveAll) { fileWatcherManager->add("/tmp/test"); fileWatcherManager->add("/tmp/test1"); fileWatcherManager->removeAll(); ASSERT_EQ(fileWatcherManager->watchedFiles().count(), 0); } TEST_F(ut_DFileWatcherManager, testDFileSystemWatcherwatchedFiles) { fileWatcherManager->add("/tmp/test"); fileWatcherManager->add("/tmp/test1"); fileWatcherManager->watchedFiles(); ASSERT_EQ(fileWatcherManager->watchedFiles().count(), 2); } dtkcore-5.7.12/tests/ut_dlicenseinfo.cpp000066400000000000000000000021061476226660600202770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include "dlicenseinfo.h" DCORE_USE_NAMESPACE TEST(ut_DLicenseInfo, testLicense) { DLicenseInfo licenseInfo; QString jsonContent = u8R"([ { "name": "dtk", "version": "5.6.8", "copyright": "Copyright 2023 THe Uniontech Company Ltd. All rights reserved.", "license": "LGPLv3" } ] )"; licenseInfo.setLicenseSearchPath(":/data/"); ASSERT_TRUE(licenseInfo.loadContent(jsonContent.toLatin1())); EXPECT_EQ(licenseInfo.componentInfos().count(), 1); ASSERT_TRUE(licenseInfo.loadFile(":/data/example-license.json")); EXPECT_EQ(licenseInfo.componentInfos().count(), 1); ASSERT_FALSE(licenseInfo.licenseContent("LGPLv3").isEmpty()); } dtkcore-5.7.12/tests/ut_dlog.cpp000066400000000000000000000017671476226660600165760ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #define private public #include "log/LogManager.h" #undef private #include "dpathbuf.h" #include "dstandardpaths.h" #include "test_helper.hpp" #include DCORE_USE_NAMESPACE TEST(ut_DLogManager, testDLogManager) { DPathBuf logPath(QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first()); logPath = logPath / "tests.log"; ASSERT_EQ(DLogManager::getlogFilePath(), logPath.toString()); } TEST(ut_DLogManager, testDefaultLogPath) { EnvGuard guard; guard.unset("HOME"); // unset HOME env will not init default log file path ASSERT_TRUE(DLogManager::getlogFilePath().contains(DStandardPaths::homePath())); } TEST(ut_DLogManager, testSetInvalidLogPath) { QString tmp = QDir::tempPath(); DLogManager::setlogFilePath(tmp); // set log file path to a dir is not supported ASSERT_NE(DLogManager::getlogFilePath(), tmp); } dtkcore-5.7.12/tests/ut_dnotifysender.cpp000066400000000000000000000022411476226660600205120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #define private public #include "dnotifysender.h" #undef private DCORE_USE_NAMESPACE struct DUtil::DNotifyData { uint m_replaceId; int m_timeOut; QString m_body; QString m_summary; QString m_appIcon; QString m_appName; QStringList m_actions; QVariantMap m_hints; }; TEST(ut_DNotifySender, notify) { DUtil::DNotifySender notifySender("summary"); notifySender.appName("appName") .replaceId(123456) .appIcon("iconName") .appBody("msg body") .actions({"1", "2"}) .timeOut(5000); //.call(); EXPECT_TRUE(notifySender.m_dbusData->m_summary == "summary"); EXPECT_TRUE(notifySender.m_dbusData->m_body == "msg body"); EXPECT_TRUE(notifySender.m_dbusData->m_replaceId == 123456); EXPECT_TRUE(notifySender.m_dbusData->m_appIcon == "iconName"); EXPECT_TRUE(notifySender.m_dbusData->m_actions == QStringList({"1", "2"})); EXPECT_TRUE(notifySender.m_dbusData->m_timeOut == 5000); } dtkcore-5.7.12/tests/ut_dpathbuf.cpp000066400000000000000000000032201476226660600174300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include "filesystem/dpathbuf.h" DCORE_USE_NAMESPACE class ut_DPathBuf : public testing::Test { protected: void SetUp() override; void TearDown() override; DPathBuf *pathBuf = nullptr; }; void ut_DPathBuf::SetUp() { pathBuf = new DPathBuf("/tmp/etc"); QDir dir("/tmp/etc/"); if (!dir.exists()) dir.mkdir("/tmp/etc/"); } void ut_DPathBuf::TearDown() { if (pathBuf) { delete pathBuf; pathBuf = nullptr; } QDir dir("/tmp/etc/"); if (dir.exists()) dir.remove("/tmp/etc/"); } TEST_F(ut_DPathBuf, testDPathBufOperatorSlashQString) { *pathBuf = *pathBuf / QString("test"); auto str = pathBuf->toString(); ASSERT_TRUE(str == "/tmp/etc/test"); } TEST_F(ut_DPathBuf, testDPathBufOperatorSlashEqualQString) { *pathBuf /= QString("test"); auto str = pathBuf->toString(); ASSERT_TRUE(str == "/tmp/etc/test"); } TEST_F(ut_DPathBuf, testDPathBufOperatorSlashChar) { *pathBuf = *pathBuf / "test"; auto str = pathBuf->toString(); ASSERT_TRUE(str == "/tmp/etc/test"); } TEST_F(ut_DPathBuf, testDPathBufOperatorSlashEqualChar) { *pathBuf /= "test"; auto str = pathBuf->toString(); ASSERT_TRUE(str == "/tmp/etc/test"); } TEST_F(ut_DPathBuf, testDPathBufJoin) { *pathBuf = pathBuf->join(QString("test")); auto str = pathBuf->toString(); ASSERT_TRUE(str == "/tmp/etc/test"); } TEST_F(ut_DPathBuf, testToString) { auto str = pathBuf->toString(); ASSERT_TRUE(str == "/tmp/etc"); } dtkcore-5.7.12/tests/ut_dpinyin.cpp000066400000000000000000000041461476226660600173150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "util/dpinyin.h" #include DCORE_USE_NAMESPACE class ut_DPinyin : public testing::Test { protected: void SetUp() override; void TearDown() override; }; void ut_DPinyin::SetUp() { } void ut_DPinyin::TearDown() { } TEST_F(ut_DPinyin, testChinese2Pinyin) { auto pinyin = Chinese2Pinyin("你好, world"); ASSERT_EQ(pinyin, "ni3hao3, world"); } TEST_F(ut_DPinyin, pinyin) { bool ok = false; QString words("深度音乐"); QStringList tones = {"shēndùyīnlè", "shēndùyīnyuè", "shēndùyīnyào", "shēndùyīnlào", "shēnduóyīnlè", "shēnduóyīnyuè", "shēnduóyīnyào", "shēnduóyīnlào"}; QStringList noneTones = {"shenduyinle", "shenduyinyue", "shenduyinyao", "shenduyinlao", "shenduoyinle", "shenduoyinyue", "shenduoyinyao", "shenduoyinlao"}; QStringList numTones = {"shen1du4yin1le4", "shen1du4yin1yue4", "shen1du4yin1yao4", "shen1du4yin1lao4", "shen1duo2yin1le4", "shen1duo2yin1yue4", "shen1duo2yin1yao4", "shen1duo2yin1lao4"}; QStringList py = pinyin(words, TS_ToneNum, &ok); ASSERT_TRUE(ok); bool isPermutation = std::is_permutation(py.begin() , py.end(), numTones.begin()); ASSERT_TRUE(isPermutation); py = pinyin(words, TS_NoneTone, &ok); ASSERT_TRUE(ok); isPermutation = std::is_permutation(py.begin() , py.end(), noneTones.begin()); ASSERT_TRUE(isPermutation); py = pinyin(words, TS_Tone, &ok); ASSERT_TRUE(ok); isPermutation = std::is_permutation(py.begin() , py.end(), tones.begin()); ASSERT_TRUE(isPermutation); } TEST_F(ut_DPinyin, firstLetters) { QStringList letters = {"sdyl", "sdyy"}; QString words("深度音乐"); QStringList ls = firstLetters(words); bool isPermutation = std::is_permutation(ls.begin() , ls.end(), letters.begin()); ASSERT_TRUE(isPermutation); } dtkcore-5.7.12/tests/ut_drecentmanager.cpp000066400000000000000000000047071476226660600206250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "util/drecentmanager.h" DCORE_USE_NAMESPACE class ut_DRecentManager: public testing::Test { protected: void SetUp() override; void TearDown() override; }; void ut_DRecentManager::SetUp() { QFile file("/tmp/test"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; file.close(); } void ut_DRecentManager::TearDown() { QFile file("/tmp/test"); if (file.exists()) file.remove(); } TEST_F(ut_DRecentManager, testDRecentManagerAddItem) { DRecentData data; data.appExec = "deepin-editor"; data.appName = "Deepin Editor"; data.mimeType = "text/plain"; bool ok = DRecentManager::addItem("/tmp/test", data); bool isFound = false; QFile file(QDir::homePath() + "/.local/share/recently-used.xbel"); QDomDocument doc; if (doc.setContent(&file)) { QDomElement rootEle = doc.documentElement(); QDomNodeList nodeList = rootEle.elementsByTagName("bookmark"); QDomElement bookmarkEle; QUrl url = QUrl::fromLocalFile("/tmp/test"); for (int i = 0; i < nodeList.size(); ++i) { const QString fileUrl = nodeList.at(i).toElement().attribute("href"); if (fileUrl == url.toEncoded(QUrl::FullyDecoded)) { bookmarkEle = nodeList.at(i).toElement(); isFound = true; break; } } ASSERT_TRUE(isFound == ok); } } TEST_F(ut_DRecentManager, testDRecentManagerRemoveItem) { QString testFile = QUrl::fromLocalFile("/tmp/test").toEncoded(QUrl::FullyDecoded); DRecentManager::removeItem(testFile); QFile file(QDir::homePath() + "/.local/share/recently-used.xbel"); QDomDocument doc; bool isFound = false; if (doc.setContent(&file)) { QDomElement rootEle = doc.documentElement(); QDomNodeList nodeList = rootEle.elementsByTagName("bookmark"); QDomElement bookmarkEle; for (int i = 0; i < nodeList.size(); ++i) { const QString fileUrl = nodeList.at(i).toElement().attribute("href"); if (fileUrl == testFile) { bookmarkEle = nodeList.at(i).toElement(); isFound = true; break; } } } ASSERT_TRUE(!isFound); } dtkcore-5.7.12/tests/ut_dsecurestring.cpp000066400000000000000000000013251476226660600205200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "dsecurestring.h" DCORE_USE_NAMESPACE class ut_DSecureString : public testing::Test { protected: void SetUp() override; void TearDown() override; DSecureString *secureString; QString string; }; void ut_DSecureString::SetUp() { secureString = new DSecureString(string); } void ut_DSecureString::TearDown() { if (secureString) { delete secureString; secureString = nullptr; } } TEST_F(ut_DSecureString, testString) { QString test = secureString->fromLatin1("test"); ASSERT_TRUE(test == QString("test")); } dtkcore-5.7.12/tests/ut_dsettings.cpp000066400000000000000000000141361476226660600176470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include "settings/dsettings.h" #include "settings/dsettingsoption.h" #include "settings/dsettingsgroup.h" #include "settings/backend/gsettingsbackend.h" #include "settings/backend/qsettingbackend.h" DCORE_USE_NAMESPACE class ut_DSettings : public testing::Test { protected: void SetUp() override; void TearDown() override; DSettings *settings; QString jsonContent; }; void ut_DSettings::SetUp() { settings = new DSettings; QFile file("/tmp/test.json"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream out(&file); jsonContent = " { \"groups\": [{ " " \"key\": \"base\", " " \"name\": \"Basic settings\", " " \"groups\": [{ " " \"key\": \"open_action\", " " \"name\": \"Open Action\", " " \"options\": [{ " " \"key\": \"alway_open_on_new\", " " \"type\": \"checkbox\", " " \"text\": \"Always Open On New Windows\", " " \"default\": true " " }] " " }] }]}"; out << jsonContent; file.close(); } void ut_DSettings::TearDown() { if (settings) { delete settings; settings = nullptr; } QFile file("/tmp/test.json"); if (file.exists()) file.remove(); } TEST_F(ut_DSettings, testDSettingSetBackend) { QPointer tmpSetting = DSettings::fromJson(jsonContent.toLatin1()); QScopedPointer scopeSettings(tmpSetting.data()); QSettingBackend qBackend("/tmp/test.json"); scopeSettings->setBackend(&qBackend); QStringList qKeys = qBackend.keys(); ASSERT_TRUE(qKeys.isEmpty()); } TEST_F(ut_DSettings, testDSettingFromJson) { QPointer tmpSetting = DSettings::fromJson(jsonContent.toLatin1()); QScopedPointer scopeSettings(tmpSetting.data()); auto keys = scopeSettings->keys(); ASSERT_TRUE(!keys.isEmpty()); } TEST_F(ut_DSettings, testDSettingFromJsonFile) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList keys = scopeSettings->keys(); ASSERT_TRUE(!keys.isEmpty()); } TEST_F(ut_DSettings, testDSettingMeta) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QJsonObject jsonObject = scopeSettings->meta(); ASSERT_TRUE(!jsonObject.isEmpty()); } TEST_F(ut_DSettings, testDSettingKeys) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList keys = scopeSettings->keys(); ASSERT_TRUE(!keys.isEmpty()); } TEST_F(ut_DSettings, testDSettingOptions) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QList> options = scopeSettings->options(); ASSERT_TRUE(!options.isEmpty()); } TEST_F(ut_DSettings, testDSettingOption) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList keys = scopeSettings->keys(); QPointer option = scopeSettings->option(keys[0]); QString optionKey = option->key(); ASSERT_TRUE(!optionKey.isEmpty()); QString optionName = option->name(); ASSERT_TRUE(optionName.isEmpty()); ASSERT_TRUE(option->canReset()); ASSERT_TRUE(option->defaultValue().toBool()); ASSERT_TRUE(option->viewType() == "checkbox"); } TEST_F(ut_DSettings, testDSettingValue) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList keys = scopeSettings->keys(); QVariant value = scopeSettings->value(keys[0]); ASSERT_TRUE(value.toBool()); } TEST_F(ut_DSettings, testDSettingGroupKeys) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList groupKeys = scopeSettings->groupKeys(); ASSERT_TRUE(!groupKeys.isEmpty()); } TEST_F(ut_DSettings, testDSettingGroups) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QList> groups = scopeSettings->groups(); ASSERT_TRUE(!groups.isEmpty()); } TEST_F(ut_DSettings, testDSettingGroup) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList keys = scopeSettings->keys(); QPointer group = scopeSettings->group("base.open_action"); QString optionKey = group->key(); ASSERT_TRUE(!optionKey.isEmpty()); } TEST_F(ut_DSettings, testDSettingGetOption) { QPointer tmpSetting = DSettings::fromJsonFile("/tmp/test.json"); QScopedPointer scopeSettings(tmpSetting.data()); QStringList keys = scopeSettings->keys(); QVariant option = scopeSettings->getOption(keys[0]); ASSERT_TRUE(option.toBool()); } TEST_F(ut_DSettings, testDSettingSync) { QPointer tmpSetting = DSettings::fromJson(jsonContent.toLatin1()); QScopedPointer scopeSettings(tmpSetting.data()); scopeSettings->sync(); QStringList keys = scopeSettings->keys(); ASSERT_TRUE(!keys.isEmpty()); } TEST_F(ut_DSettings, testDSettingReset) { QPointer tmpSetting = DSettings::fromJson(jsonContent.toLatin1()); QScopedPointer scopeSettings(tmpSetting.data()); scopeSettings->reset(); QStringList keys = scopeSettings->keys(); QVariant option = scopeSettings->getOption(keys[0]); ASSERT_TRUE(option.toBool()); } dtkcore-5.7.12/tests/ut_dsgapplication.cpp000066400000000000000000000012731476226660600206420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include "dsgapplication.h" DCORE_USE_NAMESPACE TEST(ut_DSGApplication, id) { if (!qgetenv("DSG_APP_ID").isEmpty()) { EXPECT_EQ(DSGApplication::id(), qgetenv("DSG_APP_ID")); } EXPECT_EQ(DSGApplication::id(), QCoreApplication::applicationName()); // qputenv("DTK_DISABLED_FALLBACK_APPID", "1"); // // Q_ASSERT id not empty... // EXPECT_EQ(DSGApplication::id(), ""); } TEST(ut_DSGApplication, getId) { ASSERT_EQ(DSGApplication::getId(QCoreApplication::applicationPid()), QByteArray()); } dtkcore-5.7.12/tests/ut_dstandardpaths.cpp000066400000000000000000000122171476226660600206450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "test_helper.hpp" #include "filesystem/dstandardpaths.h" DCORE_USE_NAMESPACE class ut_DStandardPaths : public testing::Test { protected: void SetUp() override; void TearDown() override; }; void ut_DStandardPaths::SetUp() { QDir dir("/tmp/etc/"); if (!dir.exists()) dir.mkdir("/tmp/etc/"); DStandardPaths::setMode(DStandardPaths::Snap); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (env.value("SNAP_USER_COMMON").isEmpty()) qputenv("SNAP_USER_COMMON", "/tmp/etc"); } void ut_DStandardPaths::TearDown() { QDir dir("/tmp/etc/"); if (dir.exists()) dir.remove("/tmp/etc/"); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (env.value("SNAP_USER_COMMON") == "/tmp/etc") qputenv("SNAP_USER_COMMON", ""); DStandardPaths::setMode(DStandardPaths::Auto); } TEST_F(ut_DStandardPaths, testDStandardPathsWritableLocation) { QString dir = DStandardPaths::writableLocation(QStandardPaths::DesktopLocation); ASSERT_TRUE(dir == "/tmp/etc"); DStandardPaths::setMode(DStandardPaths::Test); dir = DStandardPaths::writableLocation(QStandardPaths::DesktopLocation); ASSERT_TRUE(dir == QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); } TEST_F(ut_DStandardPaths, testDStandardPathsStandardLocations) { QStringList dirs = DStandardPaths::standardLocations(QStandardPaths::DesktopLocation); ASSERT_TRUE(dirs.contains("/tmp/etc")); DStandardPaths::setMode(DStandardPaths::Test); dirs = DStandardPaths::standardLocations(QStandardPaths::DesktopLocation); ASSERT_TRUE(dirs == QStandardPaths::standardLocations(QStandardPaths::DesktopLocation)); } TEST_F(ut_DStandardPaths, testD_Q) { ASSERT_EQ(DStandardPaths::locate(QStandardPaths::ApplicationsLocation, "sh"), QStandardPaths::locate(QStandardPaths::ApplicationsLocation, "sh")); ASSERT_EQ(DStandardPaths::locateAll(QStandardPaths::ApplicationsLocation, "sh"), QStandardPaths::locateAll(QStandardPaths::ApplicationsLocation, "sh")); ASSERT_EQ(DStandardPaths::findExecutable("sh"), QStandardPaths::findExecutable("sh")); } TEST_F(ut_DStandardPaths, homepath) { EnvGuard homeGuard; homeGuard.unset("HOME"); auto homePath = DStandardPaths::homePath(); ASSERT_EQ(DStandardPaths::homePath(getuid()), homePath); homeGuard.set("HOME", "/tmp/home", false); homePath = DStandardPaths::homePath(); ASSERT_EQ("/tmp/home", homePath); homeGuard.restore(); } TEST_F(ut_DStandardPaths, xdgpath) { auto testFunc = [](DStandardPaths::XDG type, const QLatin1String &env, const QByteArray &sufix, const QString &prefix = DStandardPaths::homePath()) { EnvGuard guard; guard.unset(env.data()); QString path = DStandardPaths::path(type); const QString &localpath = prefix + sufix; ASSERT_EQ(path, localpath); QByteArray custom = QByteArray("/tmp/home") + sufix; guard.set(env.data(), custom, false); qputenv(env.data(), custom.data()); path = DStandardPaths::path(type); ASSERT_EQ(path, custom); guard.restore(); }; testFunc(DStandardPaths::XDG::DataHome, QLatin1String("XDG_DATA_HOME"), "/.local/share"); testFunc(DStandardPaths::XDG::CacheHome, QLatin1String("XDG_CACHE_HOME"), "/.cache"); testFunc(DStandardPaths::XDG::ConfigHome, QLatin1String("XDG_CONFIG_HOME"), "/.config"); testFunc(DStandardPaths::XDG::RuntimeDir, QLatin1String("XDG_RUNTIME_DIR"), QByteArray::number(getuid()), "/run/user/"); } TEST_F(ut_DStandardPaths, dsgpath) { { EnvGuard guard; guard.unset("DSG_APP_DATA"); QString path = DStandardPaths::path(DStandardPaths::DSG::AppData); ASSERT_EQ(path, QString()); guard.set("DSG_APP_DATA", "/tmp/dsg"); path = DStandardPaths::path(DStandardPaths::DSG::AppData); ASSERT_EQ(path, "/tmp/dsg"); guard.restore(); } { EnvGuard guard; guard.unset("DSG_DATA_DIRS"); QString path = DStandardPaths::path(DStandardPaths::DSG::DataDir); ASSERT_EQ(path, QString(PREFIX"/share/dsg")); guard.set("DSG_DATA_DIRS", "/tmp/dsg"); path = DStandardPaths::path(DStandardPaths::DSG::DataDir); ASSERT_EQ(path, "/tmp/dsg"); guard.restore(); } } TEST_F(ut_DStandardPaths, filepath) { { EnvGuard guard; guard.unset("DSG_APP_DATA"); QString path = DStandardPaths::filePath(DStandardPaths::DSG::AppData, "filename"); ASSERT_EQ(path, QString()); guard.set("DSG_APP_DATA", "/tmp/dsg"); path = DStandardPaths::filePath(DStandardPaths::DSG::AppData, "filename"); ASSERT_EQ(path, "/tmp/dsg/filename"); guard.restore(); } QString path = DStandardPaths::filePath(DStandardPaths::XDG::CacheHome, "filename"); ASSERT_EQ(path, DStandardPaths::path(DStandardPaths::XDG::CacheHome).append("/filename")); } dtkcore-5.7.12/tests/ut_dsysinfo.cpp000066400000000000000000000356271476226660600175110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include "dsysinfo.h" #include "ddesktopentry.h" #include "test_helper.hpp" DCORE_USE_NAMESPACE class ut_DSysInfo : public testing::Test { protected: void SetUp() override { if (QLatin1String(DSYSINFO_PREFIX).isEmpty()) { GTEST_SKIP_("DSYSINFO_PREFIX not defined..."); } } void TearDown() override { } }; TEST_F(ut_DSysInfo, testOsVersion) { FileGuard guard("/tmp/etc/os-version"); DDesktopEntry entry(guard.fileName()); entry.setStringValue("UnionTech OS Desktop", "SystemName", "Version"); entry.setStringValue("统信桌面操作系统", "SystemName[zh_CN]", "Version"); entry.setStringValue("Desktop", "ProductType", "Version"); entry.setStringValue("桌面", "ProductType[zh_CN]", "Version"); entry.setStringValue("Professional", "EditionName", "Version"); entry.setStringValue("专业版", "EditionName[zh_CN]", "Version"); entry.setStringValue("20", "MajorVersion", "Version"); entry.setStringValue("100A", "MinorVersion", "Version"); entry.setStringValue("11Z18.107.109", "OsBuild", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::uosSystemName(QLocale("C")) == "UnionTech OS Desktop"); ASSERT_TRUE(DSysInfo::uosSystemName(QLocale("zh_CN")) == "统信桌面操作系统"); ASSERT_TRUE(DSysInfo::uosProductTypeName(QLocale("zh_CN")) == "桌面"); ASSERT_TRUE(DSysInfo::uosProductTypeName(QLocale("C")) == "Desktop"); ASSERT_TRUE(DSysInfo::uosEditionName(QLocale("zh_CN")) == "专业版"); ASSERT_TRUE(DSysInfo::uosEditionName(QLocale("C")) == "Professional"); ASSERT_TRUE(DSysInfo::majorVersion() == "20"); ASSERT_TRUE(DSysInfo::minorVersion() == "100A"); ASSERT_TRUE(DSysInfo::buildVersion() == "107.109"); // test minVersion.BC SP1….SP99 for (int i = 0; i < 3; ++i) { int sp = QRandomGenerator::global()->generate() % 100; entry.setStringValue(QString("%1").arg(1001 + sp * 10), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::spVersion() == (sp ? QString("SP%1").arg(sp) : QString())); } // test minVersion.D udpate1~udpate9 updateA~udpateZ for (int i = 0; i < 10; ++i) { entry.setStringValue(QString("%1").arg(1000 + i), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::udpateVersion() == (i ? QString("update%1").arg(i) : QString())); } for (char c = 'A'; c <= 'Z'; ++c) { entry.setStringValue(QString("100").append(c), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::udpateVersion() == QString("update%1").arg(c)); } // test incalide MinorVersion entry.setStringValue(QString("100?"), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::udpateVersion() == QString()); // restore MinorVersion entry.setStringValue(QString("1000"), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); // test OsBuild.B == 1 && OsBuild.D = [1, 6] ASSERT_TRUE(DSysInfo::uosType() == DSysInfo::UosDesktop); for (int i = 1; i <= 6; ++i) { entry.setStringValue(QString("%1").arg(11008.107 + i * 10), "OsBuild", "Version"); ASSERT_TRUE(entry.save()); switch (i) { case 1: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosProfessional); break; case 2: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosHome); break; case 4: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosMilitary); break; case 5: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosDeviceEdition); break; case 6: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosEducation); break; default: break; } } // test OsBuild.B == 2 && OsBuild.D = [1, 5] entry.setStringValue("12018.107", "OsBuild", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::uosType() == DSysInfo::UosServer); for (int i = 1; i <= 5; ++i) { entry.setStringValue(QString("%1").arg(12008.107 + i * 10), "OsBuild", "Version"); ASSERT_TRUE(entry.save()); switch (i) { case 1: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosEnterprise); break; case 2: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosEnterpriseC); break; case 3: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosEuler); break; case 4: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosMilitaryS); break; case 5: ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosDeviceEdition); break; default: break; } } // test OsBuild.B == 3 entry.setStringValue("13018.107", "OsBuild", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::uosType() == DSysInfo::UosDevice); ASSERT_TRUE(DSysInfo::uosEditionType() == DSysInfo::UosEnterprise); // test invalid OsBuild.B entry.setStringValue("10018.107", "OsBuild", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::uosType() == DSysInfo::UosTypeUnknown); // 社区版测试 entry.setStringValue("Community", "EditionName", "Version"); entry.setStringValue("社区版", "EditionName[zh_CN]", "Version"); entry.setStringValue("21.1.2", "MinorVersion", "Version"); entry.setStringValue("11038.107", "OsBuild", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::uosEditionName(QLocale("zh_CN")) == "社区版"); ASSERT_TRUE(DSysInfo::uosEditionName(QLocale("C")) == "Community"); ASSERT_TRUE(DSysInfo::minorVersion() == "21.1.2"); ASSERT_TRUE(DSysInfo::buildVersion() == "107"); //社区版A_BC_D模式 test minVersion.BC SP1….SP99 for (int i = 0; i < 3; ++i) { int sp = QRandomGenerator::global()->generate() % 100; entry.setStringValue(QString("%1").arg(1001 + sp * 10), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::spVersion() == (sp ? QString("SP%1").arg(sp) : QString())); } //社区版A_BC_D模式 test minVersion.D udpate1~udpate9 updateA~udpateZ for (int i = 0; i < 10; ++i) { entry.setStringValue(QString("%1").arg(1000 + i), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::udpateVersion() == (i ? QString("update%1").arg(i) : QString())); } auto dmax = [](int x, int y){ return x > y ? x : y; }; //社区版A_B_C模式 test minVersion.BC SP1….SP99 const QString &defalutSP("21.%1"); for (int i = 1; i < 3; ++i) { int sp = dmax(QRandomGenerator::global()->generate() % 100, 1); entry.setStringValue(defalutSP.arg(sp), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::spVersion() == QString("SP%1").arg(sp)); } //社区版A_B_C模式 test minVersion.D udpate1~udpate9 updateA~udpateZ const QString &defalutUpdate("21.1.%1"); for (int i = 1; i < 3; ++i) { int sp = dmax(QRandomGenerator::global()->generate() % 100, 1); entry.setStringValue(defalutUpdate.arg(sp), "MinorVersion", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::udpateVersion() == QString("update%1").arg(sp)); } // 家庭版测试 entry.setStringValue("Home", "EditionName", "Version"); entry.setStringValue("家庭版", "EditionName[zh_CN]", "Version"); entry.setStringValue("21.0", "MinorVersion", "Version"); entry.setStringValue("11078.107", "OsBuild", "Version"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::uosEditionName(QLocale("zh_CN")) == "家庭版"); ASSERT_TRUE(DSysInfo::uosEditionName(QLocale("C")) == "Home"); ASSERT_TRUE(DSysInfo::minorVersion() == "21.0"); ASSERT_TRUE(DSysInfo::buildVersion() == "107"); ASSERT_TRUE(DSysInfo::spVersion() == QStringLiteral("")); ASSERT_TRUE(DSysInfo::udpateVersion() == QStringLiteral("")); } TEST_F(ut_DSysInfo, testdistributionInfo) { FileGuard fg("/tmp/share/deepin/distribution.info"); DDesktopEntry entry(fg.fileName()); entry.setStringValue("Deepin", "Name", "Distribution"); entry.setStringValue("www.deepin.org", "WebsiteName", "Distribution"); entry.setStringValue("https://www.deepin.org", "Website", "Distribution"); entry.setStringValue("Logo.svg", "Logo", "Distribution"); entry.setStringValue("LogoLight.svg", "LogoLight", "Distribution"); entry.setStringValue("LogoTransparent.svg", "LogoTransparent", "Distribution"); entry.setStringValue("Deepin-Manufacturer", "Name", "Manufacturer"); entry.setStringValue("Deepin-Distributor", "Name", "Distributor"); ASSERT_TRUE(entry.save()); EnvGuard guard; guard.set("XDG_DATA_HOME", "/tmp/share"); ASSERT_EQ(DSysInfo::distributionInfoPath(), fg.fileName()); auto website = DSysInfo::distributionOrgWebsite(); ASSERT_EQ(website.first, "www.deepin.org"); ASSERT_EQ(website.second, "https://www.deepin.org"); ASSERT_EQ(DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Normal), "Logo.svg"); ASSERT_EQ(DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Light), "LogoLight.svg"); ASSERT_EQ(DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Symbolic), ""); // not set ASSERT_EQ(DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Transparent), "LogoTransparent.svg"); ASSERT_EQ(DSysInfo::distributionOrgName(DSysInfo::Distribution), "Deepin"); ASSERT_EQ(DSysInfo::distributionOrgName(DSysInfo::Distributor), "Deepin-Distributor"); ASSERT_EQ(DSysInfo::distributionOrgName(DSysInfo::Manufacturer), "Deepin-Manufacturer"); guard.restore(); } TEST_F(ut_DSysInfo, osRelease) { FileGuard fg("/tmp/etc/os-release"); DDesktopEntry entry(fg.fileName()); entry.setStringValue("Deepin", "ID", "Release"); entry.setStringValue("20.9", "VERSION_ID", "Release"); entry.setStringValue("Deepin 20.9", "PRETTY_NAME", "Release"); ASSERT_TRUE(entry.save()); ASSERT_EQ(DSysInfo::operatingSystemName(), "Deepin 20.9"); ASSERT_EQ(DSysInfo::productType(), DSysInfo::Deepin); ASSERT_EQ(DSysInfo::productTypeString(), "Deepin"); ASSERT_EQ(DSysInfo::productVersion(), "20.9"); // isDeepin ASSERT_TRUE(DSysInfo::isDeepin()); entry.setStringValue("Uos", "ID", "Release"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::isDeepin()); entry.setStringValue("arch", "ID", "Release"); ASSERT_TRUE(entry.save()); ASSERT_FALSE(DSysInfo::isDeepin()); QString types[] = {"UnknownType", "Deepin", "Arch", "CentOS", "Debian", "Fedora", "LinuxMint", "Manjaro", "openSUSE","SailfishOS", "Ubuntu", "Uos", "Gentoo", "NixOS"}; for (int i = DSysInfo::UnknownType; i <= DSysInfo::NixOS; ++i) { entry.setStringValue(types[i], "ID", "Release"); ASSERT_TRUE(entry.save()); ASSERT_EQ(DSysInfo::productType(), DSysInfo::ProductType(i)); } } TEST_F(ut_DSysInfo, isDDE) { FileGuard fg("/tmp/etc/os-release"); DDesktopEntry entry(fg.fileName()); entry.setStringValue("Deepin 20.9", "PRETTY_NAME", "Release"); entry.setStringValue("Deepin", "ID", "Release"); entry.setStringValue("20.9", "VERSION_ID", "Release"); ASSERT_TRUE(entry.save()); FileGuard fg2("/tmp/etc/deepin-version"); DDesktopEntry entry2(fg2.fileName()); entry2.setStringValue("20.9", "Version", "Release"); entry2.setStringValue("Desktop", "Type", "Release"); ASSERT_TRUE(entry2.save()); // isDeepin && deepinType valid ASSERT_TRUE(DSysInfo::isDeepin()); ASSERT_TRUE(DSysInfo::isDDE()); // isDeepin but deepinType unknow entry2.setStringValue("Unknown", "Type", "Release"); ASSERT_TRUE(entry2.save()); ASSERT_TRUE(DSysInfo::isDeepin()); ASSERT_FALSE(DSysInfo::isDDE()); // !isDeepin && XDG_SESSION_DESKTOP == dde or deepin { entry.setStringValue("Unknown", "ID", "Release"); ASSERT_TRUE(entry.save()); ASSERT_FALSE(DSysInfo::isDeepin()); EnvGuard guard; guard.set("XDG_SESSION_DESKTOP", "dde"); ASSERT_TRUE(DSysInfo::isDDE()); guard.restore(); guard.set("XDG_SESSION_DESKTOP", "deepin"); ASSERT_TRUE(DSysInfo::isDDE()); guard.restore(); guard.set("XDG_SESSION_DESKTOP", "Unknown"); ASSERT_FALSE(DSysInfo::isDDE()); guard.restore(); } } TEST_F(ut_DSysInfo, deepinVersion) { FileGuard fg("/tmp/etc/deepin-version"); DDesktopEntry entry(fg.fileName()); entry.setStringValue("20.9", "Version", "Release"); entry.setStringValue("Desktop", "Type", "Release"); entry.setStringValue("社区版", "Type[zh_CN]", "Release"); entry.setStringValue("Y2020E0001", "Edition", "Release"); entry.setStringValue("Y2020CR001", "Copyright", "Release"); entry.setStringValue("build1", "Buildid", "Addition"); //entry.setStringValue("", "Milestone", "Addition"); ASSERT_TRUE(entry.save()); ASSERT_EQ(DSysInfo::deepinTypeDisplayName(QLocale("C")), "Desktop"); ASSERT_EQ(DSysInfo::deepinTypeDisplayName(QLocale("zh_CN")), "社区版"); ASSERT_EQ(DSysInfo::deepinVersion(), "20.9"); ASSERT_EQ(DSysInfo::deepinEdition(), "Y2020E0001"); ASSERT_EQ(DSysInfo::deepinCopyright(), "Y2020CR001"); qInfo() << "DSysInfo::deepinType()" << DSysInfo::deepinType(); ASSERT_EQ(DSysInfo::deepinType(), DSysInfo::DeepinDesktop); { // isCommunityEdition Not Uos FileGuard fg("/tmp/etc/os-release"); DDesktopEntry entry(fg.fileName()); entry.setStringValue("Deepin", "ID", "Release"); ASSERT_TRUE(entry.save()); ASSERT_TRUE(DSysInfo::isCommunityEdition()); entry.setStringValue("Uos", "ID", "Release"); ASSERT_TRUE(entry.save()); ASSERT_FALSE(DSysInfo::isCommunityEdition()); } entry.setStringValue("Professional", "Type", "Release"); ASSERT_TRUE(entry.save()); ASSERT_EQ(DSysInfo::deepinType(), DSysInfo::DeepinProfessional); ASSERT_FALSE(DSysInfo::isCommunityEdition()); entry.setStringValue("Server", "Type", "Release"); ASSERT_TRUE(entry.save()); ASSERT_EQ(DSysInfo::deepinType(), DSysInfo::DeepinServer); ASSERT_FALSE(DSysInfo::isCommunityEdition()); entry.setStringValue("Personal", "Type", "Release"); ASSERT_TRUE(entry.save()); ASSERT_EQ(DSysInfo::deepinType(), DSysInfo::DeepinPersonal); ASSERT_FALSE(DSysInfo::isCommunityEdition()); } TEST_F(ut_DSysInfo, other) { qDebug() << DSysInfo::computerName(); qDebug() << DSysInfo::memoryInstalledSize(); qDebug() << DSysInfo::memoryTotalSize(); qDebug() << DSysInfo::systemDiskSize(); } dtkcore-5.7.12/tests/ut_dtextencoding.cpp000066400000000000000000000240441476226660600205010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtextencoding.h" #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #else #include #endif DCORE_USE_NAMESPACE class ut_DTextEncoding : public testing::Test { public: static void SetUpTestCase(); bool rewriteTempFile(const QByteArray &data); void removeTempFile(); static bool canLoadUchardet; static bool canLoadICU; static QString tmpFileName; static QByteArray dataGB18030; static QByteArray dataEUC_JP; static QByteArray dataKOI8_R; protected: void TearDown() override; }; bool ut_DTextEncoding::canLoadUchardet = false; bool ut_DTextEncoding::canLoadICU = false; QString ut_DTextEncoding::tmpFileName; // Utf8 Chinese Text(Hex): 中文测试一二三四123456789abcdefgh QByteArray ut_DTextEncoding::dataGB18030 = "\xd6\xd0\xce\xc4\xb2\xe2\xca\xd4\xd2\xbb\xb6\xfe\xc8\xfd\xcb\xc4\x31\x32\x33\x34\x35" "\x36\x37\x38\x39\x61\x62\x63\x64\x65\x66\x67\x68"; // Utf8 Japanese Text(Hex): 日本語のテスト ワン ツー スリー フォー 123456789abcdefgh QByteArray ut_DTextEncoding::dataEUC_JP = "\xc6\xfc\xcb\xdc\xb8\xec\xa4\xce\xa5\xc6\xa5\xb9\xa5\xc8\x20\xa5\xef\xa5\xf3\x20\xa5\xc4\xa1\xbc\x20\xa5\xb9\xa5\xea\xa1\xbc" "\x20\xa5\xd5\xa5\xa9\xa1\xbc\x20\x31\x32\x33\x34\x35\x36\x37\x38\x39\x61\x62\x63\x64\x65\x66\x67\x68"; // Utf8 Russian Text(Hex): Русский тест раз два три четыре 123456789abcdefgh QByteArray ut_DTextEncoding::dataKOI8_R = "\xf2\xd5\xd3\xd3\xcb\xc9\xca\x20\xd4\xc5\xd3\xd4\x20\xd2\xc1\xda\x20\xc4\xd7\xc1\x20\xd4\xd2\xc9\x20\xde\xc5\xd4\xd9\xd2\xc5" "\x20\x31\x32\x33\x34\x35\x36\x37\x38\x39\x61\x62\x63\x64\x65\x66\x67\x68"; void ut_DTextEncoding::SetUpTestCase() { QLibrary uchardet("libuchardet", "0"); if (!uchardet.isLoaded()) { canLoadUchardet = uchardet.load(); if (canLoadUchardet) { uchardet.unload(); } } QLibrary icuuc("libicuuc"); if (icuuc.isLoaded()) { canLoadICU = icuuc.load(); if (canLoadICU) { icuuc.unload(); } } } bool ut_DTextEncoding::rewriteTempFile(const QByteArray &data) { QTemporaryFile tmpFile; if (!tmpFile.open()) { return false; } tmpFileName = tmpFile.fileName(); tmpFile.setAutoRemove(false); tmpFile.write(data); tmpFile.close(); return true; } void ut_DTextEncoding::removeTempFile() { if (QFile::exists(tmpFileName)) { QFile::remove(tmpFileName); } } void ut_DTextEncoding::TearDown() { removeTempFile(); } TEST_F(ut_DTextEncoding, testDetectTextEncode) { // Default encoding is utf-8. ASSERT_EQ("UTF-8", DTextEncoding::detectTextEncoding("")); ASSERT_EQ("UTF-8", DTextEncoding::detectTextEncoding("12345678ABCDEFG")); ASSERT_EQ("GB18030", DTextEncoding::detectTextEncoding(dataGB18030)); ASSERT_EQ("EUC-JP", DTextEncoding::detectTextEncoding(dataEUC_JP)); ASSERT_EQ("KOI8-R", DTextEncoding::detectTextEncoding(dataKOI8_R)); } TEST_F(ut_DTextEncoding, testDetectTextEncodeWithUchardet) { if (canLoadUchardet) { QByteArray uchardetEncoding("EUC-TW"); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto encode = QStringConverter::encodingForName(uchardetEncoding); ASSERT_FALSE(encode); #else // QTextCodec not suppotted EUC-TW. QTextCodec *codec = QTextCodec::codecForName(uchardetEncoding); ASSERT_EQ(codec, nullptr); #endif // Utf8 text: 繁體中文測試一二三四 QByteArray dataZhTraditional("\u7e41\u9ad4\u4e2d\u6587\u6e2c\u8a66\u4e00\u4e8c\u4e09\u56db"); QByteArray dataEUC_TW; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataZhTraditional, dataEUC_TW, uchardetEncoding)); ASSERT_EQ(uchardetEncoding, DTextEncoding::detectTextEncoding(dataEUC_TW)); QByteArray convertGB18030; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataEUC_TW, convertGB18030, "GB18030")); QByteArray convertUTF8; ASSERT_TRUE(DTextEncoding::convertTextEncoding(convertGB18030, convertUTF8, "UTF-8")); ASSERT_EQ(dataZhTraditional, convertUTF8); } } TEST_F(ut_DTextEncoding, testDetectFileEncode) { bool isOk = false; ASSERT_EQ("", DTextEncoding::detectFileEncoding(tmpFileName, &isOk)); ASSERT_FALSE(isOk); ASSERT_TRUE(rewriteTempFile("")); ASSERT_EQ("UTF-8", DTextEncoding::detectFileEncoding(tmpFileName, &isOk)); ASSERT_TRUE(isOk); ASSERT_TRUE(rewriteTempFile(dataGB18030)); ASSERT_EQ("GB18030", DTextEncoding::detectFileEncoding(tmpFileName, &isOk)); ASSERT_TRUE(isOk); ASSERT_TRUE(rewriteTempFile(dataEUC_JP)); ASSERT_EQ("EUC-JP", DTextEncoding::detectFileEncoding(tmpFileName, &isOk)); ASSERT_TRUE(isOk); ASSERT_TRUE(rewriteTempFile(dataKOI8_R)); ASSERT_EQ("KOI8-R", DTextEncoding::detectFileEncoding(tmpFileName, &isOk)); ASSERT_TRUE(isOk); } TEST_F(ut_DTextEncoding, testConvertTextEncoding) { QByteArray dataUTF_8; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataGB18030, dataUTF_8, "UTF-8")); ASSERT_EQ("UTF-8", DTextEncoding::detectTextEncoding(dataUTF_8)); // QStringConverter not support GB18030. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QTextCodec *codec = QTextCodec::codecForName("GB18030"); ASSERT_EQ(codec->toUnicode(dataGB18030).toUtf8(), dataUTF_8); QByteArray convertedGB18030; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataUTF_8, convertedGB18030, "GB18030")); ASSERT_EQ(dataGB18030, convertedGB18030); #endif // Convert with multi bytes encoding. QByteArray dataUTF_16; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataUTF_8, dataUTF_16, "UTF-16")); ASSERT_EQ("UTF-16", DTextEncoding::detectTextEncoding(dataUTF_16)); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // Qt6 using utf-16 string by default, not utf-8. auto fromUtf16 = QStringDecoder(QStringDecoder::Utf16); QString strUtf16 = fromUtf16.decode(dataUTF_16); ASSERT_EQ(strUtf16, QString::fromUtf8(dataUTF_8)); #else codec = QTextCodec::codecForName("UTF-16"); ASSERT_EQ(codec->toUnicode(dataUTF_16).toUtf8(), dataUTF_8); #endif QByteArray convertedUTF8; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataUTF_16, convertedUTF8, "UTF-8")); ASSERT_EQ(dataUTF_8, convertedUTF8); QByteArray dataUTF_32; ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataUTF_8, dataUTF_32, "UTF-32")); ASSERT_EQ("UTF-32", DTextEncoding::detectTextEncoding(dataUTF_32)); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto fromUtf32 = QStringDecoder(QStringDecoder::Utf32); QString strUtf32 = fromUtf32.decode(dataUTF_32); ASSERT_EQ(strUtf32, QString::fromUtf8(dataUTF_8)); #else codec = QTextCodec::codecForName("UTF-32"); ASSERT_EQ(codec->toUnicode(dataUTF_32).toUtf8(), dataUTF_8); #endif ASSERT_TRUE(DTextEncoding::convertTextEncoding(dataUTF_32, convertedUTF8, "UTF-8")); ASSERT_EQ(dataUTF_8, convertedUTF8); } TEST_F(ut_DTextEncoding, testConvertTextEncodingWithError) { QByteArray dataUTF_8; ASSERT_FALSE(DTextEncoding::convertTextEncoding(dataGB18030, dataUTF_8, "ERROR")); ASSERT_FALSE(DTextEncoding::convertTextEncoding(dataGB18030, dataUTF_8, "KOI8-R")); QByteArray tmpUTF_8Error = "\x31\x32\x33\xFF\xFF\xFF\x31\x32\x33"; QByteArray tmpUTF_16; QString error; int converted = 0; bool ret = DTextEncoding::convertTextEncodingEx(tmpUTF_8Error, tmpUTF_16, "UTF-16", "UTF-8", &error, &converted); ASSERT_FALSE(ret); ASSERT_FALSE(error.isEmpty()); ASSERT_EQ(converted, 3); QByteArray tmpUTF_8Error2 = "\xFF\xFF"; converted = 3; ret = DTextEncoding::convertTextEncodingEx(tmpUTF_8Error2, tmpUTF_16, "UTF-16", "UTF-8", &error, &converted); ASSERT_FALSE(ret); ASSERT_EQ(converted, 0); } TEST_F(ut_DTextEncoding, testConvertFileEncoding) { ASSERT_TRUE(rewriteTempFile(dataGB18030)); ASSERT_TRUE(DTextEncoding::convertFileEncoding(tmpFileName, "UTF-8")); ASSERT_EQ("UTF-8", DTextEncoding::detectFileEncoding(tmpFileName)); ASSERT_TRUE(DTextEncoding::convertFileEncoding(tmpFileName, "UTF-32")); ASSERT_EQ("UTF-32", DTextEncoding::detectFileEncoding(tmpFileName)); ASSERT_FALSE(DTextEncoding::convertFileEncoding("", "UTF-32")); } TEST_F(ut_DTextEncoding, testConvertFileEncodingTo) { QString tmpConvertFileName("/tmp/ut_DTextEncoding_temp_testConvertFileEncodingTo.txt"); if (QFile::exists(tmpConvertFileName)) { ASSERT_TRUE(QFile::remove(tmpConvertFileName)); } ASSERT_TRUE(rewriteTempFile(dataGB18030)); ASSERT_TRUE(DTextEncoding::convertFileEncodingTo(tmpFileName, tmpConvertFileName, "GB18030")); ASSERT_TRUE(QFile::exists(tmpConvertFileName)); ASSERT_TRUE(DTextEncoding::convertFileEncodingTo(tmpFileName, tmpConvertFileName, "UTF-8")); ASSERT_TRUE(QFile::exists(tmpConvertFileName)); ASSERT_EQ("UTF-8", DTextEncoding::detectFileEncoding(tmpConvertFileName)); ASSERT_TRUE(DTextEncoding::convertFileEncodingTo(tmpFileName, tmpConvertFileName, "UTF-32")); ASSERT_EQ("UTF-32", DTextEncoding::detectFileEncoding(tmpConvertFileName)); ASSERT_TRUE(QFile::remove(tmpConvertFileName)); } TEST_F(ut_DTextEncoding, testConvertFileEncodingToWithError) { QString tmpConvertFileName("/tmp/ut_DTextEncoding_temp_testConvertFileEncodingToWithError.txt"); if (QFile::exists(tmpConvertFileName)) { ASSERT_TRUE(QFile::remove(tmpConvertFileName)); } ASSERT_FALSE(DTextEncoding::convertFileEncodingTo("", tmpConvertFileName, "UTF-32")); ASSERT_FALSE(DTextEncoding::convertFileEncodingTo(tmpFileName, "", "UTF-32")); ASSERT_FALSE(DTextEncoding::convertFileEncodingTo(tmpFileName, tmpConvertFileName, "ERROR")); ASSERT_FALSE(QFile::exists(tmpConvertFileName)); ASSERT_TRUE(rewriteTempFile(dataGB18030)); ASSERT_FALSE(DTextEncoding::convertFileEncodingTo(tmpFileName, tmpConvertFileName, "EUC-JP")); ASSERT_FALSE(QFile::exists(tmpConvertFileName)); } dtkcore-5.7.12/tests/ut_dthreadutils.cpp000066400000000000000000000147501476226660600203410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2020 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include DCORE_USE_NAMESPACE #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) class ThreadUtils : public QObject { Q_OBJECT public Q_SLOTS: void testCallInMainThread(); }; void ThreadUtils::testCallInMainThread() { DThreadUtil::runInMainThread([]() { bool result = QThread::currentThread() == QCoreApplication::instance()->thread(); ASSERT_TRUE(result); }); auto fe = QtConcurrent::run([] { ASSERT_TRUE(DThreadUtil::runInMainThread([](QThread *thread) -> bool { return QThread::currentThread() == QCoreApplication::instance()->thread() && QThread::currentThread() != thread; }, QThread::currentThread())); }); ASSERT_TRUE(QTest::qWaitFor([&] { return fe.isFinished(); })); } class ut_DThreadUtils : public testing::Test { public: virtual void SetUp() { m_threadutil = new ThreadUtils(); } virtual void TearDown() { delete m_threadutil; } protected: ThreadUtils *m_threadutil = nullptr; }; TEST_F(ut_DThreadUtils, CallInMainThread) { ASSERT_TRUE(m_threadutil); m_threadutil->testCallInMainThread(); } #else class ut_DThreadUtils :public testing::Test{ public: virtual void SetUp() { t = new QThread(); t->start(); m_threadutil = new DThreadUtils(t); } virtual void TearDown() { t->exit(); t->wait(); delete t; delete m_threadutil; } protected: QThread *t{nullptr}; DThreadUtils *m_threadutil{nullptr}; }; class QWorker : public QObject { Q_OBJECT public: explicit QWorker(QObject *parent = nullptr):QObject(parent){} ~QWorker() = default; public Q_SLOTS: int testFunc(int i, double j) { int r =qFloor(i + j); wait(); emit testFuncTrigger(r); return r; } void setWaitForSecs(int sec){ m_waitSecs = sec; } void wait() { std::unique_lock lock(m_mutex); m_cv.wait_for(lock, std::chrono::seconds(m_waitSecs)); } void notifyOne() { m_cv.notify_one(); } Q_SIGNALS: void testFuncTrigger(int v); private: std::mutex m_mutex; std::condition_variable m_cv; int m_waitSecs = 2; }; class CallableObject{ public: CallableObject() = default; ~CallableObject() = default; QString operator()(const QString &str){ s += str; std::this_thread::sleep_for(std::chrono::microseconds(100)); return s; } QString testFunc(const QString &){ return s; } private: QString s{"CallableObject: "}; }; TEST_F(ut_DThreadUtils, testThread) { auto tmp = m_threadutil->thread(); EXPECT_EQ(tmp, t); } TEST_F(ut_DThreadUtils, testRunWithQObj) { QWorker w; QSignalSpy spy(&w, &QWorker::testFuncTrigger); auto result = m_threadutil->run(&w, &QWorker::testFunc, 10, 24.6); std::this_thread::sleep_for(std::chrono::microseconds(100)); EXPECT_TRUE(result.isStarted()); EXPECT_TRUE(result.isRunning()); w.notifyOne(); result.waitForFinished(); EXPECT_TRUE(result.isFinished()); auto raw = result.result(); EXPECT_EQ(raw, 34); EXPECT_EQ(spy.count(), 1); } TEST_F(ut_DThreadUtils,testRunWithLambda) { auto threadId1 = std::this_thread::get_id(); auto result = m_threadutil->run([](decltype(threadId1) id){ EXPECT_NE(std::this_thread::get_id(), id); return true; }, threadId1); result.waitForFinished(); auto raw = result.result(); EXPECT_TRUE(raw); } TEST_F(ut_DThreadUtils,testRunWithCallableObj) { CallableObject obj; QString tmp{"Hello"}; auto result1 = m_threadutil->run(obj, tmp); result1.waitForFinished(); auto raw1 = result1.result(); EXPECT_EQ(raw1, QString{"CallableObject: Hello"}); auto result2 = m_threadutil->run(&obj, &CallableObject::testFunc, tmp); result2.waitForFinished(); auto raw2 = result2.result(); EXPECT_EQ(raw2, QString{"CallableObject: "}); } TEST_F(ut_DThreadUtils, testExecWithQObj) { QWorker w; w.setWaitForSecs(0); QSignalSpy spy(&w, SIGNAL(testFuncTrigger(int))); auto result = m_threadutil->exec(&w, &QWorker::testFunc, 10, 24.6); EXPECT_EQ(result, 34); EXPECT_EQ(spy.count(), 1); } TEST_F(ut_DThreadUtils, testExecWithLambda) { auto threadId1 = std::this_thread::get_id(); auto result = m_threadutil->exec ( [](decltype(threadId1) id) { EXPECT_NE(std::this_thread::get_id(), id); return true; }, threadId1); EXPECT_TRUE(result); } TEST_F(ut_DThreadUtils, testExecWithCallableObj) { CallableObject obj; QString tmp{"Hello"}; auto result1 = m_threadutil->exec(obj, tmp); EXPECT_EQ(result1, QString{"CallableObject: Hello"}); auto result2 = m_threadutil->exec(&obj, &CallableObject::testFunc, tmp); EXPECT_EQ(result2, QString{"CallableObject: "}); } TEST_F(ut_DThreadUtils, testDirectlyInvoke) { DThreadUtils tu(QThread::currentThread()); QWorker w; w.setWaitForSecs(0); QSignalSpy spy(&w, SIGNAL(testFuncTrigger(int))); auto result = tu.run(&w, &QWorker::testFunc, 10, 24.6); auto raw = result.result(); // no wait EXPECT_EQ(raw, 34); EXPECT_EQ(spy.count(), 1); } TEST_F(ut_DThreadUtils, testCancel) { CallableObject obj; QString tmp{"Hello"}; int cancelCounter{0}; auto result1 = m_threadutil->run(obj, tmp); auto cancelResult = result1.onCanceled([&cancelCounter]() { cancelCounter += 1; return QString{"failed"}; }); result1.cancel(); EXPECT_FALSE(result1.isFinished()); EXPECT_FALSE(result1.isValid()); EXPECT_TRUE(result1.isCanceled()); cancelResult.waitForFinished(); EXPECT_EQ(cancelCounter, 1); EXPECT_EQ(cancelResult.result(), QString{"failed"}); } TEST_F(ut_DThreadUtils, testDestructCancel) { auto w = new QWorker{}; auto failedCounter{0}; auto result = m_threadutil->run(w, &QWorker::testFunc, 10, 24.6); delete w; auto failedResult = result.onFailed([&failedCounter]() { failedCounter += 1; return -1; }); EXPECT_FALSE(result.isValid()); failedResult.waitForFinished(); EXPECT_EQ(failedCounter, 1); EXPECT_EQ(failedResult.result(), -1); } #endif #include "ut_dthreadutils.moc" dtkcore-5.7.12/tests/ut_dtimeunitformatter.cpp000066400000000000000000000036441476226660600215730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "util/dtimeunitformatter.h" #include "filesystem/dtrashmanager.h" DCORE_USE_NAMESPACE class ut_DTimeUnitFormatter : public testing::Test { protected: void SetUp() override; void TearDown() override; DTimeUnitFormatter timeUnitFormatter; }; void ut_DTimeUnitFormatter::SetUp() { } void ut_DTimeUnitFormatter::TearDown() { } TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterFormatAs) { qreal result0 = timeUnitFormatter.formatAs(120, DTimeUnitFormatter::Seconds, DTimeUnitFormatter::Minute); ASSERT_TRUE(qFuzzyCompare(result0, 2)); qreal result1 = timeUnitFormatter.formatAs(2, DTimeUnitFormatter::Minute, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(result1, 120)); qreal result2 = timeUnitFormatter.formatAs(2, DTimeUnitFormatter::Seconds, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(result2, 2)); } TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterFormat) { QPair result = timeUnitFormatter.format(120, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(result.first, 2)); ASSERT_EQ(result.second, DTimeUnitFormatter::Minute); } TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterFormatAsUnitList) { QList> result = timeUnitFormatter.formatAsUnitList(121, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(result[0].first, 121)); ASSERT_EQ(result[0].second, DTimeUnitFormatter::Seconds); } TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterUnitStr) { ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Seconds), "s"); ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Minute), "m"); ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Hour), "h"); ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Day), "d"); } dtkcore-5.7.12/tests/ut_dtrashmanager.cpp000066400000000000000000000025351476226660600204630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include "filesystem/dstandardpaths.h" #include "filesystem/dtrashmanager.h" DCORE_USE_NAMESPACE class ut_DTrashManager : public testing::Test { protected: void SetUp() override; void TearDown() override; QString path; }; void ut_DTrashManager::SetUp() { DStandardPaths::setMode(DStandardPaths::Auto); path = DStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/Trash/files"; QFile file(path + "/test"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; file.close(); } void ut_DTrashManager::TearDown() { QFile file("/tmp/test"); if (file.exists()) file.remove(); } TEST_F(ut_DTrashManager, testDTrashManagerTrashIsEmpty) { DTrashManager::instance()->moveToTrash(path + "/test"); bool ok = DTrashManager::instance()->trashIsEmpty(); ASSERT_TRUE(ok = ok ? ok : !ok); } TEST_F(ut_DTrashManager, testDTrashManagerCleanTrash) { bool ok = DTrashManager::instance()->cleanTrash(); ASSERT_TRUE(ok = ok ? ok : !ok); } TEST_F(ut_DTrashManager, testDTrashManagerMoveToTrash) { bool ok = DTrashManager::instance()->moveToTrash(path + "/test"); ASSERT_TRUE(ok = ok ? ok : !ok); } dtkcore-5.7.12/tests/ut_dutil.cpp000066400000000000000000000075701476226660600167700ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ut_dutil.h" #include #include "util/dtimeunitformatter.h" #include "util/ddisksizeformatter.h" DCORE_USE_NAMESPACE void ut_DUtil::SetUpTestCase() { //qDebug() << "*****************" << __FUNCTION__; } void ut_DUtil::TearDownTestCase() { //qDebug() << "*****************" << __FUNCTION__; } void ut_DUtil::SetUp() { QDir dir("/tmp/etc/"); if (!dir.exists()) dir.mkdir("/tmp/etc/"); } void ut_DUtil::TearDown() { QDir dir("/tmp/etc/"); if (dir.exists()) dir.remove("/tmp/etc/"); } TEST_F(ut_DUtil, testTimeFormatter) { const DTimeUnitFormatter timeFormatter; // 3600 seconds == 1 hour const auto r0 = timeFormatter.format(3600, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(r0.first, 1) && r0.second == DTimeUnitFormatter::Hour); // 86400 seconds == 1 day const auto r1 = timeFormatter.format(86400, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(r1.first, 1) && r1.second == DTimeUnitFormatter::Day); // 129600 seconds == 1.5 day const auto r3 = timeFormatter.format(129600, DTimeUnitFormatter::Seconds); ASSERT_TRUE(qFuzzyCompare(1.5, r3.first) && r3.second == DTimeUnitFormatter::Day); // 1.5 day == 36 hours const auto r4 = timeFormatter.formatAs(1.5, DTimeUnitFormatter::Day, DTimeUnitFormatter::Hour); ASSERT_TRUE(qFuzzyCompare(r4, 36)); } TEST_F(ut_DUtil, testTimeFormatterList) { const DTimeUnitFormatter timeFormatter; // 135120.5 Minutes == 93 days + 20 hours + 30 seconds const auto r = timeFormatter.formatAsUnitList(135120.5, DTimeUnitFormatter::Minute); ASSERT_TRUE(qFuzzyCompare(r[0].first, 93) && r[0].second == DTimeUnitFormatter::Day); ASSERT_TRUE(qFuzzyCompare(r[1].first, 20) && r[1].second == DTimeUnitFormatter::Hour); ASSERT_TRUE(qFuzzyCompare(r[2].first, 30) && r[2].second == DTimeUnitFormatter::Seconds); } TEST_F(ut_DUtil, testDiskFormatter) { const DDiskSizeFormatter diskFormatter1000 = DDiskSizeFormatter(); // 1000 K == 1 M const auto i0 = diskFormatter1000.format(1000, DDiskSizeFormatter::K); ASSERT_TRUE(qFuzzyCompare(i0.first, 1) && i0.second == DDiskSizeFormatter::M); // 1000 K == 1000000 B const auto i1 = diskFormatter1000.formatAs(1000, DDiskSizeFormatter::K, DDiskSizeFormatter::B); ASSERT_TRUE(qFuzzyCompare(i1, 1000000)); } TEST_F(ut_DUtil, testDiskFormatterList) { const DDiskSizeFormatter diskFormatter = DDiskSizeFormatter(); // 1351223412.1234 KB == 1 TB + 351 GB + 223 MB + 412 KB + 123.4 B const auto r = diskFormatter.formatAsUnitList(1351223412.1234, DDiskSizeFormatter::K); ASSERT_TRUE(qFuzzyCompare(r[0].first, 1) && r[0].second == DDiskSizeFormatter::T); ASSERT_TRUE(qFuzzyCompare(r[1].first, 351) && r[1].second == DDiskSizeFormatter::G); ASSERT_TRUE(qFuzzyCompare(r[2].first, 223) && r[2].second == DDiskSizeFormatter::M); ASSERT_TRUE(qFuzzyCompare(r[3].first, 412) && r[3].second == DDiskSizeFormatter::K); // TODO: test failed // Q_ASSERT(r[4].first == 123.4 && r[4].second == DiskSizeFormatter::B); } TEST_F(ut_DUtil, testDiskFormatter1024) { const DDiskSizeFormatter diskFormatter = DDiskSizeFormatter().rate(1024); // 1024 K == 1 M const auto d0 = diskFormatter.format(1024, DDiskSizeFormatter::K); ASSERT_TRUE(qFuzzyCompare(d0.first, 1) && d0.second == DDiskSizeFormatter::M); // 100000000000 B == 93.13225746154785 G const auto d1 = diskFormatter.format(100000000000, DDiskSizeFormatter::B); ASSERT_TRUE(qFuzzyCompare(93.13225746154785, d1.first) && d1.second == DDiskSizeFormatter::G); // 100000000000 B == 0.09094947017729282 T const auto d2 = diskFormatter.formatAs(100000000000, DDiskSizeFormatter::B, DDiskSizeFormatter::T); ASSERT_TRUE(qFuzzyCompare(0.09094947017729282, d2)); } dtkcore-5.7.12/tests/ut_dutil.h000066400000000000000000000012161476226660600164240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include "dtkcore_global.h" #include #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) #include "dtimedloop.h" DCORE_USE_NAMESPACE #endif // 有返回值的 lambda 表达式、函数里面使用 ASSERT_XXX // 总之,不管有没有返回值,用它就对了 #ifndef HAVE_FUN #define HAVE_FUN(X) [&](){X;}(); #endif class ut_DUtil : public testing::Test { protected: static void SetUpTestCase(); static void TearDownTestCase(); virtual void SetUp(); virtual void TearDown(); }; dtkcore-5.7.12/tests/ut_dvtablehook.cpp000066400000000000000000000102671476226660600201460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "testso.h" #include class ut_DVtableHook : public testing::Test { public: static void SetUpTestCase() { qDebug() << "*****************" << __FUNCTION__; } static void TearDownTestCase() { qDebug() << "*****************" << __FUNCTION__; } virtual void SetUp(); virtual void TearDown(); virtual ~ut_DVtableHook() {} }; void ut_DVtableHook::SetUp() { } void ut_DVtableHook::TearDown() { } using namespace TestClass; DCORE_USE_NAMESPACE static char test(A *obj, int v) { qDebug() << Q_FUNC_INFO << obj << v; return 'x'; } static char test2(A *obj, int v, bool v2) { qDebug() << Q_FUNC_INFO << obj << v << v2; return 'y'; } TEST_F(ut_DVtableHook, objectFun2ObjectFun) { A *a = new A(); B *b = new B(); ASSERT_TRUE(DVtableHook::overrideVfptrFun(a, &A::test, b, &B::test)); ASSERT_TRUE(DVtableHook::hasVtable(a)); ASSERT_EQ(a->test(0), 'b'); DVtableHook::resetVfptrFun(a, &A::test); ASSERT_EQ(a->test(0), 'a'); delete a; ASSERT_TRUE(!DVtableHook::hasVtable(a)); delete b; } TEST_F(ut_DVtableHook, objectFun2Fun) { A *a = new A(); ASSERT_TRUE(DVtableHook::overrideVfptrFun(a, &A::test, &test)); ASSERT_EQ(a->test(1), 'x'); DVtableHook::resetVtable(a); ASSERT_TRUE(!DVtableHook::hasVtable(a)); delete a; } TEST_F(ut_DVtableHook, objectFun2StdFun) { A *a = new A(); ASSERT_TRUE(DVtableHook::overrideVfptrFun(a, &A::test, std::bind(&test2, std::placeholders::_1, std::placeholders::_2, true))); ASSERT_EQ(a->test(2), 'y'); DVtableHook::resetVtable(a); ASSERT_TRUE(!DVtableHook::hasVtable(a)); // not support // A *a2 = new A(); // ASSERT_TRUE(DVtableHook::overrideVfptrFun(a2, &A::test, std::bind(&test2, std::placeholders::_1, std::placeholders::_2, false))); // ASSERT_TRUE(!a2->test(2)); // DVtableHook::resetVtable(a2); // ASSERT_TRUE(!DVtableHook::hasVtable(a2)); delete a; } TEST_F(ut_DVtableHook, objectFun2LambdaFun) { A *a = new A(); auto lambda1 = [](A *obj, int v) { qDebug() << Q_FUNC_INFO << obj << v; return '1'; }; auto lambda2 = [](A *obj, int v) { qDebug() << Q_FUNC_INFO << obj << v; return '2'; }; ASSERT_TRUE(DVtableHook::overrideVfptrFun(a, &A::test, lambda1)); ASSERT_EQ(a->test(3), '1'); ASSERT_TRUE(DVtableHook::overrideVfptrFun(a, &A::test, lambda2)); ASSERT_EQ(a->test(3), '2'); DVtableHook::resetVtable(a); ASSERT_TRUE(!DVtableHook::hasVtable(a)); delete a; } TEST_F(ut_DVtableHook, fun2ObjectFun) { B *b = new B(); ASSERT_TRUE(DVtableHook::overrideVfptrFun(&A::test, b, &B::test)); A *a = new A(); ASSERT_TRUE(DVtableHook::getVtableOfObject(a) == DVtableHook::getVtableOfClass
()); ASSERT_EQ(a->test(4), 'b'); delete a; delete b; } TEST_F(ut_DVtableHook, fun2Fun) { ASSERT_TRUE(DVtableHook::overrideVfptrFun(&A::test, &test)); A *a = new A(); ASSERT_EQ(a->test(5), 'x'); delete a; } TEST_F(ut_DVtableHook, fun2StdFun) { A *a = new A(); ASSERT_TRUE(DVtableHook::overrideVfptrFun(&A::test, std::bind(&test2, std::placeholders::_1, std::placeholders::_2, true))); ASSERT_EQ(a->test(6), 'y'); DVtableHook::resetVtable(a); ASSERT_TRUE(!DVtableHook::hasVtable(a)); delete a; } TEST_F(ut_DVtableHook, fun2LambdaFun) { A *a = new A(); auto lambda = [](A *obj, int v) { qDebug() << Q_FUNC_INFO << obj << v; return 'z'; }; ASSERT_TRUE(DVtableHook::overrideVfptrFun(&A::test, lambda)); ASSERT_EQ(a->test(7), 'z'); DVtableHook::resetVtable(a); ASSERT_TRUE(!DVtableHook::hasVtable(a)); delete a; } TEST_F(ut_DVtableHook, testRTTI) { A *c1 = new C(); auto original = typeid(*c1).name(); auto lambda3 = [](C *obj, int v) { qDebug() << Q_FUNC_INFO << obj << v; return '3'; }; ASSERT_TRUE(DVtableHook::overrideVfptrFun(dynamic_cast(c1), &C::test, lambda3)); ASSERT_EQ(c1->test(0), '3'); ASSERT_EQ(typeid(*c1).name(), original); delete c1; } dtkcore-5.7.12/tests/ut_gsettingsbackend.cpp000066400000000000000000000047301476226660600211610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include "settings/dsettings.h" #include "settings/dsettingsoption.h" #include "settings/dsettingsgroup.h" #include "settings/backend/gsettingsbackend.h" #include "settings/backend/qsettingbackend.h" DCORE_USE_NAMESPACE class ut_GSettings : public testing::Test { protected: void SetUp() override; void TearDown() override; DSettings *settings = nullptr; GSettingsBackend * gSettingBackend = nullptr; QString jsonContent; }; void ut_GSettings::SetUp() { GTEST_SKIP_("Do not test GSettingsBackend. schema was removed..."); QFile file("/tmp/test.json"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream out(&file); jsonContent = " { " " \"gsettings\": { " " \"id\": \"com.deepin.dtk\"," " \"path\": \"/dtk/deepin/deepin-terminal/\" " "}," " \"groups\": [{ " " \"key\": \"base\", " " \"name\": \"Basic settings\", " " \"groups\": [{ " " \"key\": \"open_action\", " " \"name\": \"Open Action\", " " \"options\": [{ " " \"key\": \"paletteType\", " " \"type\": \"checkbox\", " " \"text\": \"Always Open On New Windows\", " " \"default\": true " " }] " " }] }]" "}"; out << jsonContent; file.close(); settings = DSettings::fromJson(jsonContent.toLatin1()); gSettingBackend = new GSettingsBackend(settings); } void ut_GSettings::TearDown() { if (gSettingBackend) { delete gSettingBackend; gSettingBackend = nullptr; } if (settings) { delete settings; settings = nullptr; } QFile file("/tmp/test.json"); if (file.exists()) file.remove(); } TEST_F(ut_GSettings, testGSettingBackendKeys) { QStringList qKeys = gSettingBackend->keys(); ASSERT_TRUE(!qKeys.isEmpty()); } TEST_F(ut_GSettings, testGSettingBackendGetOption) { QStringList qKeys = gSettingBackend->keys(); ASSERT_TRUE(!qKeys.isEmpty()); QVariant value = gSettingBackend->getOption(qKeys[0]); ASSERT_TRUE(!value.toString().isEmpty()); } dtkcore-5.7.12/tests/ut_qsettingsbackend.cpp000066400000000000000000000055651476226660600212020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include "settings/dsettings.h" #include "settings/dsettingsoption.h" #include "settings/dsettingsgroup.h" #include "settings/backend/gsettingsbackend.h" #include "settings/backend/qsettingbackend.h" DCORE_USE_NAMESPACE class ut_QSettingsBackend : public testing::Test { protected: void SetUp() override; void TearDown() override; QString jsonContent; QString iniContent; }; void ut_QSettingsBackend::SetUp() { QFile file("/tmp/test.ini"); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream out(&file); jsonContent = " { \"groups\": [{ " " \"key\": \"base\", " " \"name\": \"Basic settings\", " " \"groups\": [{ " " \"key\": \"open_action\", " " \"name\": \"Open Action\", " " \"options\": [{ " " \"key\": \"alway_open_on_new\", " " \"type\": \"checkbox\", " " \"text\": \"Always Open On New Windows\", " " \"default\": true " " }] " " }] }]}"; iniContent = "[Test] \n \ value=false "; out << iniContent; file.close(); } void ut_QSettingsBackend::TearDown() { QFile file("/tmp/test.ini"); if (file.exists()) file.remove(); } TEST_F(ut_QSettingsBackend, testQSettingsBackendKeys) { DSettings tmpSetting; QSettingBackend qBackend("/tmp/test.ini"); tmpSetting.setBackend(&qBackend); QStringList qKeys = qBackend.keys(); ASSERT_TRUE(!qKeys.isEmpty()); } TEST_F(ut_QSettingsBackend, testQSettingsBackendGetOption) { QPointer tmpSetting = DSettings::fromJson(jsonContent.toLatin1()); QScopedPointer scopeSettings(tmpSetting.data()); QSettingBackend qBackend("/tmp/test.ini"); scopeSettings->setBackend(&qBackend); scopeSettings->sync(); QStringList qKeys = qBackend.keys(); ASSERT_TRUE(!qKeys.isEmpty()); QVariant value = qBackend.getOption("Test"); ASSERT_TRUE(!value.toBool()); } TEST_F(ut_QSettingsBackend, testQSettingsBackendDoOption) { QPointer tmpSetting = DSettings::fromJson(jsonContent.toLatin1()); QScopedPointer scopeSettings(tmpSetting.data()); QSettingBackend qBackend("/tmp/test.ini"); scopeSettings->setBackend(&qBackend); Q_EMIT qBackend.setOption("Test", true); QStringList qKeys = qBackend.keys(); ASSERT_TRUE(!qKeys.isEmpty()); QVariant value = qBackend.getOption("Test"); ASSERT_TRUE(!value.toBool()); // ensure `DSettings` is released before `SettingBackend` if `doSetOption` maybe execute. scopeSettings.reset(); } dtkcore-5.7.12/tests/ut_singleton.cpp000066400000000000000000000031521476226660600176410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ut_singleton.h" #include #include #include Singleton::Singleton(QObject *parent) : QObject(parent), count(0) { } MultiSingletonTester::MultiSingletonTester(QObject *parent) : QObject(parent) { } void MultiSingletonTester::run() { Singleton::ref().count.ref(); } int MultiSingletonTester::count() const { #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) return Singleton::ref().count.loadRelaxed(); #else return Singleton::ref().count.load(); #endif } TEST(ut_DSingleton, testDSingleton) { const int exampleCount = 5; QVector threads; QVector testers; threads.reserve(exampleCount); testers.reserve(exampleCount); for (int i = 0; i < exampleCount; i++) { auto thread = new QThread(); auto tester = new MultiSingletonTester; tester->moveToThread(thread); QObject::connect(thread, &QThread::started, tester, &MultiSingletonTester::run); threads.push_back(thread); testers.push_back(tester); thread->start(); } for (auto thread : threads) { thread->quit(); } ASSERT_TRUE(QTest::qWaitFor([threads] { for (auto thread : threads) { if (!thread->isFinished()) { return false; } } return true; })); for (auto tester : testers) { ASSERT_EQ(tester->count(), exampleCount); } qDeleteAll(threads); qDeleteAll(testers); } dtkcore-5.7.12/tests/ut_singleton.h000066400000000000000000000011461476226660600173070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include "base/dsingleton.h" class Singleton : public QObject , public Dtk::Core::DSingleton { Q_OBJECT friend class Dtk::Core::DSingleton; public: explicit Singleton(QObject *parent = nullptr); QAtomicInt count; }; class MultiSingletonTester : public QObject { Q_OBJECT public: explicit MultiSingletonTester(QObject *parent = nullptr); int count() const; public Q_SLOTS: void run(); }; dtkcore-5.7.12/toolGenerate/000077500000000000000000000000001476226660600157105ustar00rootroot00000000000000dtkcore-5.7.12/toolGenerate/dconfig2cpp/000077500000000000000000000000001476226660600201065ustar00rootroot00000000000000dtkcore-5.7.12/toolGenerate/dconfig2cpp/dconf-example_meta.hpp000066400000000000000000000527161476226660600243620ustar00rootroot00000000000000/** * This file is generated by dconfig2cpp. * Command line arguments: ./dconfig2cpp -p ./dtkcore/toolGenerate/dconfig2cpp ./dtkcore/tests/data/dconf-example.meta.json * Generation time: 2025-01-14T10:54:59 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. * If you need to change the content, please modify the dconfig2cpp tool. */ #ifndef DCONF-EXAMPLE_META_H #define DCONF-EXAMPLE_META_H #include #include #include #include #include #include class dconf-example_meta : public QObject { Q_OBJECT Q_PROPERTY(QList array READ array WRITE setArray NOTIFY arrayChanged) Q_PROPERTY(QList array_map READ array_map WRITE setArray_map NOTIFY array_mapChanged) Q_PROPERTY(QList array_map_struct READ array_map_struct WRITE setArray_map_struct NOTIFY array_map_structChanged) Q_PROPERTY(bool canExit READ canExit WRITE setCanExit NOTIFY canExitChanged) Q_PROPERTY(QString key2 READ key2 WRITE setKey2 NOTIFY key2Changed) Q_PROPERTY(QString key3 READ key3 WRITE setKey3 NOTIFY key3Changed) Q_PROPERTY(QVariantMap map READ map WRITE setMap NOTIFY mapChanged) Q_PROPERTY(QVariantMap map_array READ map_array WRITE setMap_array NOTIFY map_arrayChanged) Q_PROPERTY(double number READ number WRITE setNumber NOTIFY numberChanged) Q_PROPERTY(double numberDouble READ numberDouble WRITE setNumberDouble NOTIFY numberDoubleChanged) Q_PROPERTY(bool publicConfig READ publicConfig WRITE setPublicConfig NOTIFY publicConfigChanged) Q_PROPERTY(QVariantMap struct READ struct WRITE setStruct NOTIFY structChanged) public: explicit dconf-example_meta(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-example_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-example_meta(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-example_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } ~dconf-example_meta() { if (m_config.loadRelaxed()) { m_config.loadRelaxed()->deleteLater(); } } QList array() const { return p_array; } void setArray(const QList &value) { auto oldValue = p_array; p_array = value; markPropertySet(0); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("array"), value); }); } if (p_array != oldValue) { Q_EMIT arrayChanged(); } } QList array_map() const { return p_array_map; } void setArray_map(const QList &value) { auto oldValue = p_array_map; p_array_map = value; markPropertySet(1); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("array_map"), value); }); } if (p_array_map != oldValue) { Q_EMIT array_mapChanged(); } } QList array_map_struct() const { return p_array_map_struct; } void setArray_map_struct(const QList &value) { auto oldValue = p_array_map_struct; p_array_map_struct = value; markPropertySet(2); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("array_map_struct"), value); }); } if (p_array_map_struct != oldValue) { Q_EMIT array_map_structChanged(); } } bool canExit() const { return p_canExit; } void setCanExit(const bool &value) { auto oldValue = p_canExit; p_canExit = value; markPropertySet(3); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("canExit"), value); }); } if (p_canExit != oldValue) { Q_EMIT canExitChanged(); } } QString key2() const { return p_key2; } void setKey2(const QString &value) { auto oldValue = p_key2; p_key2 = value; markPropertySet(4); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("key2"), value); }); } if (p_key2 != oldValue) { Q_EMIT key2Changed(); } } QString key3() const { return p_key3; } void setKey3(const QString &value) { auto oldValue = p_key3; p_key3 = value; markPropertySet(5); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("key3"), value); }); } if (p_key3 != oldValue) { Q_EMIT key3Changed(); } } QVariantMap map() const { return p_map; } void setMap(const QVariantMap &value) { auto oldValue = p_map; p_map = value; markPropertySet(6); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("map"), value); }); } if (p_map != oldValue) { Q_EMIT mapChanged(); } } QVariantMap map_array() const { return p_map_array; } void setMap_array(const QVariantMap &value) { auto oldValue = p_map_array; p_map_array = value; markPropertySet(7); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("map_array"), value); }); } if (p_map_array != oldValue) { Q_EMIT map_arrayChanged(); } } double number() const { return p_number; } void setNumber(const double &value) { auto oldValue = p_number; p_number = value; markPropertySet(8); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("number"), value); }); } if (p_number != oldValue) { Q_EMIT numberChanged(); } } double numberDouble() const { return p_numberDouble; } void setNumberDouble(const double &value) { auto oldValue = p_numberDouble; p_numberDouble = value; markPropertySet(9); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("numberDouble"), value); }); } if (p_numberDouble != oldValue) { Q_EMIT numberDoubleChanged(); } } bool publicConfig() const { return p_publicConfig; } void setPublicConfig(const bool &value) { auto oldValue = p_publicConfig; p_publicConfig = value; markPropertySet(10); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("publicConfig"), value); }); } if (p_publicConfig != oldValue) { Q_EMIT publicConfigChanged(); } } QVariantMap struct() const { return p_struct; } void setStruct(const QVariantMap &value) { auto oldValue = p_struct; p_struct = value; markPropertySet(11); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("struct"), value); }); } if (p_struct != oldValue) { Q_EMIT structChanged(); } } Q_SIGNALS: void arrayChanged(); void array_mapChanged(); void array_map_structChanged(); void canExitChanged(); void key2Changed(); void key3Changed(); void mapChanged(); void map_arrayChanged(); void numberChanged(); void numberDoubleChanged(); void publicConfigChanged(); void structChanged(); private: void initialize(DTK_CORE_NAMESPACE::DConfig *config) { Q_ASSERT(!m_config.loadRelaxed()); m_config.storeRelaxed(config); if (testPropertySet(0)) { config->setValue(QStringLiteral("array"), QVariant::fromValue(p_array)); } else { updateValue(QStringLiteral("array"), QVariant::fromValue(p_array)); } if (testPropertySet(1)) { config->setValue(QStringLiteral("array_map"), QVariant::fromValue(p_array_map)); } else { updateValue(QStringLiteral("array_map"), QVariant::fromValue(p_array_map)); } if (testPropertySet(2)) { config->setValue(QStringLiteral("array_map_struct"), QVariant::fromValue(p_array_map_struct)); } else { updateValue(QStringLiteral("array_map_struct"), QVariant::fromValue(p_array_map_struct)); } if (testPropertySet(3)) { config->setValue(QStringLiteral("canExit"), QVariant::fromValue(p_canExit)); } else { updateValue(QStringLiteral("canExit"), QVariant::fromValue(p_canExit)); } if (testPropertySet(4)) { config->setValue(QStringLiteral("key2"), QVariant::fromValue(p_key2)); } else { updateValue(QStringLiteral("key2"), QVariant::fromValue(p_key2)); } if (testPropertySet(5)) { config->setValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); } else { updateValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); } if (testPropertySet(6)) { config->setValue(QStringLiteral("map"), QVariant::fromValue(p_map)); } else { updateValue(QStringLiteral("map"), QVariant::fromValue(p_map)); } if (testPropertySet(7)) { config->setValue(QStringLiteral("map_array"), QVariant::fromValue(p_map_array)); } else { updateValue(QStringLiteral("map_array"), QVariant::fromValue(p_map_array)); } if (testPropertySet(8)) { config->setValue(QStringLiteral("number"), QVariant::fromValue(p_number)); } else { updateValue(QStringLiteral("number"), QVariant::fromValue(p_number)); } if (testPropertySet(9)) { config->setValue(QStringLiteral("numberDouble"), QVariant::fromValue(p_numberDouble)); } else { updateValue(QStringLiteral("numberDouble"), QVariant::fromValue(p_numberDouble)); } if (testPropertySet(10)) { config->setValue(QStringLiteral("publicConfig"), QVariant::fromValue(p_publicConfig)); } else { updateValue(QStringLiteral("publicConfig"), QVariant::fromValue(p_publicConfig)); } if (testPropertySet(11)) { config->setValue(QStringLiteral("struct"), QVariant::fromValue(p_struct)); } else { updateValue(QStringLiteral("struct"), QVariant::fromValue(p_struct)); } connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { updateValue(key); }, Qt::DirectConnection); } void updateValue(const QString &key, const QVariant &fallback = QVariant()) { Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); const QVariant &value = m_config.loadRelaxed()->value(key, fallback); if (key == QStringLiteral("array")) { auto newValue = qvariant_cast>(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_array != newValue) { p_array = newValue; Q_EMIT arrayChanged(); } }); return; } if (key == QStringLiteral("array_map")) { auto newValue = qvariant_cast>(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_array_map != newValue) { p_array_map = newValue; Q_EMIT array_mapChanged(); } }); return; } if (key == QStringLiteral("array_map_struct")) { auto newValue = qvariant_cast>(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_array_map_struct != newValue) { p_array_map_struct = newValue; Q_EMIT array_map_structChanged(); } }); return; } if (key == QStringLiteral("canExit")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_canExit != newValue) { p_canExit = newValue; Q_EMIT canExitChanged(); } }); return; } if (key == QStringLiteral("key2")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_key2 != newValue) { p_key2 = newValue; Q_EMIT key2Changed(); } }); return; } if (key == QStringLiteral("key3")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_key3 != newValue) { p_key3 = newValue; Q_EMIT key3Changed(); } }); return; } if (key == QStringLiteral("map")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_map != newValue) { p_map = newValue; Q_EMIT mapChanged(); } }); return; } if (key == QStringLiteral("map_array")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_map_array != newValue) { p_map_array = newValue; Q_EMIT map_arrayChanged(); } }); return; } if (key == QStringLiteral("number")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_number != newValue) { p_number = newValue; Q_EMIT numberChanged(); } }); return; } if (key == QStringLiteral("numberDouble")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_numberDouble != newValue) { p_numberDouble = newValue; Q_EMIT numberDoubleChanged(); } }); return; } if (key == QStringLiteral("publicConfig")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_publicConfig != newValue) { p_publicConfig = newValue; Q_EMIT publicConfigChanged(); } }); return; } if (key == QStringLiteral("struct")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_struct != newValue) { p_struct = newValue; Q_EMIT structChanged(); } }); return; } } inline void markPropertySet(const int index) { if (index < 32) { m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); return; } Q_UNREACHABLE(); } inline bool testPropertySet(const int index) const { if (index < 32) { return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); } Q_UNREACHABLE(); } QAtomicPointer m_config = nullptr; QList p_array { QList{QVariant(QStringLiteral("value1")), QVariant(QStringLiteral("value2"))} }; QList p_array_map { QList{QVariant(QVariantMap{{QStringLiteral("key1"), QVariant(QStringLiteral("value1"))}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}})} }; QList p_array_map_struct { QList{QVariant(QVariantMap{{QStringLiteral("key1"), QVariant(QVariantMap{{QStringLiteral("field1"), QVariant(QStringLiteral("value1"))}})}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}})} }; bool p_canExit { true }; QString p_key2 { QStringLiteral("125") }; QString p_key3 { QStringLiteral("application") }; QVariantMap p_map { QVariantMap{{QStringLiteral("key1"), QVariant(QStringLiteral("value1"))}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}} }; QVariantMap p_map_array { QVariantMap{{QStringLiteral("key1"), QVariant(QList{QVariant(QStringLiteral("value1"))})}, {QStringLiteral("key2"), QVariant(QList{QVariant(QStringLiteral("value2"))})}} }; double p_number { 1 }; double p_numberDouble { 1 }; bool p_publicConfig { true }; QVariantMap p_struct { QVariantMap{{QStringLiteral("key1"), QVariant(QStringLiteral("value1"))}, {QStringLiteral("key2"), QVariant(QStringLiteral("value2"))}} }; QAtomicInteger m_propertySetStatus0 = 0; }; #endif // DCONF-EXAMPLE_META_H dtkcore-5.7.12/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp000066400000000000000000000204401476226660600304510ustar00rootroot00000000000000/** * This file is generated by dconfig2cpp. * Command line arguments: ./dconfig2cpp -p ./dtkcore/toolGenerate/dconfig2cpp ./dtkcore/tests/data/dconf-example_other_app_configure.meta.json * Generation time: 2025-01-14T10:54:59 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. * If you need to change the content, please modify the dconfig2cpp tool. */ #ifndef DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H #define DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H #include #include #include #include #include #include class dconf-example_other_app_configure_meta : public QObject { Q_OBJECT Q_PROPERTY(QString appPrivate READ appPrivate WRITE setAppPrivate NOTIFY appPrivateChanged) Q_PROPERTY(QString appPublic READ appPublic WRITE setAppPublic NOTIFY appPublicChanged) public: explicit dconf-example_other_app_configure_meta(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-example_other_app_configure_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-example_other_app_configure_meta(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-example_other_app_configure_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } ~dconf-example_other_app_configure_meta() { if (m_config.loadRelaxed()) { m_config.loadRelaxed()->deleteLater(); } } QString appPrivate() const { return p_appPrivate; } void setAppPrivate(const QString &value) { auto oldValue = p_appPrivate; p_appPrivate = value; markPropertySet(0); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("appPrivate"), value); }); } if (p_appPrivate != oldValue) { Q_EMIT appPrivateChanged(); } } QString appPublic() const { return p_appPublic; } void setAppPublic(const QString &value) { auto oldValue = p_appPublic; p_appPublic = value; markPropertySet(1); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("appPublic"), value); }); } if (p_appPublic != oldValue) { Q_EMIT appPublicChanged(); } } Q_SIGNALS: void appPrivateChanged(); void appPublicChanged(); private: void initialize(DTK_CORE_NAMESPACE::DConfig *config) { Q_ASSERT(!m_config.loadRelaxed()); m_config.storeRelaxed(config); if (testPropertySet(0)) { config->setValue(QStringLiteral("appPrivate"), QVariant::fromValue(p_appPrivate)); } else { updateValue(QStringLiteral("appPrivate"), QVariant::fromValue(p_appPrivate)); } if (testPropertySet(1)) { config->setValue(QStringLiteral("appPublic"), QVariant::fromValue(p_appPublic)); } else { updateValue(QStringLiteral("appPublic"), QVariant::fromValue(p_appPublic)); } connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { updateValue(key); }, Qt::DirectConnection); } void updateValue(const QString &key, const QVariant &fallback = QVariant()) { Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); const QVariant &value = m_config.loadRelaxed()->value(key, fallback); if (key == QStringLiteral("appPrivate")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_appPrivate != newValue) { p_appPrivate = newValue; Q_EMIT appPrivateChanged(); } }); return; } if (key == QStringLiteral("appPublic")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_appPublic != newValue) { p_appPublic = newValue; Q_EMIT appPublicChanged(); } }); return; } } inline void markPropertySet(const int index) { if (index < 32) { m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); return; } Q_UNREACHABLE(); } inline bool testPropertySet(const int index) const { if (index < 32) { return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); } Q_UNREACHABLE(); } QAtomicPointer m_config = nullptr; QString p_appPrivate { QStringLiteral("appPrivate") }; QString p_appPublic { QStringLiteral("publicValue") }; QAtomicInteger m_propertySetStatus0 = 0; }; #endif // DCONF-EXAMPLE_OTHER_APP_CONFIGURE_META_H dtkcore-5.7.12/toolGenerate/dconfig2cpp/dconf-global_meta.hpp000066400000000000000000000152301476226660600241550ustar00rootroot00000000000000/** * This file is generated by dconfig2cpp. * Command line arguments: ./dconfig2cpp -p ./dtkcore/toolGenerate/dconfig2cpp ./dtkcore/tests/data/dconf-global.meta.json * Generation time: 2025-01-14T10:54:59 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. * If you need to change the content, please modify the dconfig2cpp tool. */ #ifndef DCONF-GLOBAL_META_H #define DCONF-GLOBAL_META_H #include #include #include #include #include #include class dconf-global_meta : public QObject { Q_OBJECT Q_PROPERTY(QString key3 READ key3 WRITE setKey3 NOTIFY key3Changed) public: explicit dconf-global_meta(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-global_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-global_meta(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit dconf-global_meta(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } ~dconf-global_meta() { if (m_config.loadRelaxed()) { m_config.loadRelaxed()->deleteLater(); } } QString key3() const { return p_key3; } void setKey3(const QString &value) { auto oldValue = p_key3; p_key3 = value; markPropertySet(0); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("key3"), value); }); } if (p_key3 != oldValue) { Q_EMIT key3Changed(); } } Q_SIGNALS: void key3Changed(); private: void initialize(DTK_CORE_NAMESPACE::DConfig *config) { Q_ASSERT(!m_config.loadRelaxed()); m_config.storeRelaxed(config); if (testPropertySet(0)) { config->setValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); } else { updateValue(QStringLiteral("key3"), QVariant::fromValue(p_key3)); } connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { updateValue(key); }, Qt::DirectConnection); } void updateValue(const QString &key, const QVariant &fallback = QVariant()) { Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); const QVariant &value = m_config.loadRelaxed()->value(key, fallback); if (key == QStringLiteral("key3")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_key3 != newValue) { p_key3 = newValue; Q_EMIT key3Changed(); } }); return; } } inline void markPropertySet(const int index) { if (index < 32) { m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); return; } Q_UNREACHABLE(); } inline bool testPropertySet(const int index) const { if (index < 32) { return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); } Q_UNREACHABLE(); } QAtomicPointer m_config = nullptr; QString p_key3 { QStringLiteral("global") }; QAtomicInteger m_propertySetStatus0 = 0; }; #endif // DCONF-GLOBAL_META_H dtkcore-5.7.12/toolGenerate/qdbusxml2cpp/000077500000000000000000000000001476226660600203345ustar00rootroot00000000000000dtkcore-5.7.12/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.ManagerAdaptor.cpp000066400000000000000000000072741476226660600315470ustar00rootroot00000000000000/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp ./dtkcore/src/dbus/org.desktopspec.ConfigManager.Manager.xml -a ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.ManagerAdaptor -i ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.Manager.h * * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd. * * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ #include "./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.ManagerAdaptor.h" #include #include #include #include #include #include #include /* * Implementation of adaptor class ManagerAdaptor */ ManagerAdaptor::ManagerAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } ManagerAdaptor::~ManagerAdaptor() { // destructor } QStringList ManagerAdaptor::keyList() const { // get the value of property keyList return qvariant_cast< QStringList >(parent()->property("keyList")); } QString ManagerAdaptor::version() const { // get the value of property version return qvariant_cast< QString >(parent()->property("version")); } QString ManagerAdaptor::description(const QString &key, const QString &language) { // handle method call org.desktopspec.ConfigManager.Manager.description QString description; QMetaObject::invokeMethod(parent(), "description", Q_RETURN_ARG(QString, description), Q_ARG(QString, key), Q_ARG(QString, language)); return description; } bool ManagerAdaptor::isDefaultValue(const QString &key) { // handle method call org.desktopspec.ConfigManager.Manager.isDefaultValue bool isDefaultValue; QMetaObject::invokeMethod(parent(), "isDefaultValue", Q_RETURN_ARG(bool, isDefaultValue), Q_ARG(QString, key)); return isDefaultValue; } QString ManagerAdaptor::name(const QString &key, const QString &language) { // handle method call org.desktopspec.ConfigManager.Manager.name QString name; QMetaObject::invokeMethod(parent(), "name", Q_RETURN_ARG(QString, name), Q_ARG(QString, key), Q_ARG(QString, language)); return name; } QString ManagerAdaptor::permissions(const QString &key) { // handle method call org.desktopspec.ConfigManager.Manager.permissions QString permissions; QMetaObject::invokeMethod(parent(), "permissions", Q_RETURN_ARG(QString, permissions), Q_ARG(QString, key)); return permissions; } void ManagerAdaptor::release() { // handle method call org.desktopspec.ConfigManager.Manager.release QMetaObject::invokeMethod(parent(), "release"); } void ManagerAdaptor::reset(const QString &key) { // handle method call org.desktopspec.ConfigManager.Manager.reset QMetaObject::invokeMethod(parent(), "reset", Q_ARG(QString, key)); } void ManagerAdaptor::setValue(const QString &key, const QDBusVariant &value) { // handle method call org.desktopspec.ConfigManager.Manager.setValue QMetaObject::invokeMethod(parent(), "setValue", Q_ARG(QString, key), Q_ARG(QDBusVariant, value)); } QDBusVariant ManagerAdaptor::value(const QString &key) { // handle method call org.desktopspec.ConfigManager.Manager.value QDBusVariant value; QMetaObject::invokeMethod(parent(), "value", Q_RETURN_ARG(QDBusVariant, value), Q_ARG(QString, key)); return value; } QString ManagerAdaptor::visibility(const QString &key) { // handle method call org.desktopspec.ConfigManager.Manager.visibility QString visibility; QMetaObject::invokeMethod(parent(), "visibility", Q_RETURN_ARG(QString, visibility), Q_ARG(QString, key)); return visibility; } dtkcore-5.7.12/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.ManagerAdaptor.h000066400000000000000000000074031476226660600312060ustar00rootroot00000000000000/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp ./dtkcore/src/dbus/org.desktopspec.ConfigManager.Manager.xml -a ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.ManagerAdaptor -i ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.Manager.h * * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #ifndef ORG_DESKTOPSPEC_CONFIGMANAGER_MANAGERADAPTOR_H #define ORG_DESKTOPSPEC_CONFIGMANAGER_MANAGERADAPTOR_H #include #include #include "./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.Manager.h" QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QStringList; class QVariant; QT_END_NAMESPACE /* * Adaptor class for interface org.desktopspec.ConfigManager.Manager */ class ManagerAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.desktopspec.ConfigManager.Manager") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: ManagerAdaptor(QObject *parent); virtual ~ManagerAdaptor(); public: // PROPERTIES Q_PROPERTY(QStringList keyList READ keyList) QStringList keyList() const; Q_PROPERTY(QString version READ version) QString version() const; public Q_SLOTS: // METHODS QString description(const QString &key, const QString &language); bool isDefaultValue(const QString &key); QString name(const QString &key, const QString &language); QString permissions(const QString &key); void release(); void reset(const QString &key); void setValue(const QString &key, const QDBusVariant &value); QDBusVariant value(const QString &key); QString visibility(const QString &key); Q_SIGNALS: // SIGNALS void valueChanged(const QString &key); }; #endif dtkcore-5.7.12/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManagerAdaptor.cpp000066400000000000000000000034071476226660600301700ustar00rootroot00000000000000/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp ./dtkcore/src/dbus/org.desktopspec.ConfigManager.xml -a ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManagerAdaptor -i ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.h * * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd. * * This is an auto-generated file. * Do not edit! All changes made to it will be lost. */ #include "./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManagerAdaptor.h" #include #include #include #include #include #include #include /* * Implementation of adaptor class ConfigManagerAdaptor */ ConfigManagerAdaptor::ConfigManagerAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } ConfigManagerAdaptor::~ConfigManagerAdaptor() { // destructor } QDBusObjectPath ConfigManagerAdaptor::acquireManager(const QString &appid, const QString &name, const QString &subpath) { // handle method call org.desktopspec.ConfigManager.acquireManager QDBusObjectPath path; QMetaObject::invokeMethod(parent(), "acquireManager", Q_RETURN_ARG(QDBusObjectPath, path), Q_ARG(QString, appid), Q_ARG(QString, name), Q_ARG(QString, subpath)); return path; } void ConfigManagerAdaptor::sync(const QString &path) { // handle method call org.desktopspec.ConfigManager.sync QMetaObject::invokeMethod(parent(), "sync", Q_ARG(QString, path)); } void ConfigManagerAdaptor::update(const QString &path) { // handle method call org.desktopspec.ConfigManager.update QMetaObject::invokeMethod(parent(), "update", Q_ARG(QString, path)); } dtkcore-5.7.12/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManagerAdaptor.h000066400000000000000000000040651476226660600276360ustar00rootroot00000000000000/* * This file was generated by qdbusxml2cpp version 0.8 * Command line was: qdbusxml2cpp ./dtkcore/src/dbus/org.desktopspec.ConfigManager.xml -a ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManagerAdaptor -i ./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.h * * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd. * * This is an auto-generated file. * This file may have been hand-edited. Look for HAND-EDIT comments * before re-generating it. */ #ifndef ORG_DESKTOPSPEC_CONFIGMANAGERADAPTOR_H #define ORG_DESKTOPSPEC_CONFIGMANAGERADAPTOR_H #include #include #include "./dtkcore/toolGenerate/qdbusxml2cpp/org.desktopspec.ConfigManager.h" QT_BEGIN_NAMESPACE class QByteArray; template class QList; template class QMap; class QString; class QStringList; class QVariant; QT_END_NAMESPACE /* * Adaptor class for interface org.desktopspec.ConfigManager */ class ConfigManagerAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.desktopspec.ConfigManager") Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "") public: ConfigManagerAdaptor(QObject *parent); virtual ~ConfigManagerAdaptor(); public: // PROPERTIES public Q_SLOTS: // METHODS QDBusObjectPath acquireManager(const QString &appid, const QString &name, const QString &subpath); void sync(const QString &path); void update(const QString &path); Q_SIGNALS: // SIGNALS }; #endif dtkcore-5.7.12/tools/000077500000000000000000000000001476226660600144205ustar00rootroot00000000000000dtkcore-5.7.12/tools/CMakeLists.txt000066400000000000000000000002521476226660600171570ustar00rootroot00000000000000add_subdirectory(dci) add_subdirectory(deepin-os-release) add_subdirectory(qdbusxml2cpp) add_subdirectory(settings) add_subdirectory(ch2py) add_subdirectory(dconfig2cpp) dtkcore-5.7.12/tools/ch2py/000077500000000000000000000000001476226660600154455ustar00rootroot00000000000000dtkcore-5.7.12/tools/ch2py/CMakeLists.txt000066400000000000000000000012351476226660600202060ustar00rootroot00000000000000set(TARGET_NAME ch2py) set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) set(CMAKE_AUTORCC ON) add_executable(${BIN_NAME} ${PROJECT_SOURCE_DIR}/src/util/dpinyin.cpp ${PROJECT_SOURCE_DIR}/src/util/util.qrc main.cpp ) target_link_libraries(${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core ) target_include_directories(${BIN_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include/util ${PROJECT_SOURCE_DIR}/include/global ) set_target_properties(${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME}) install(TARGETS ${BIN_NAME} DESTINATION "${TOOL_INSTALL_DIR}") dtkcore-5.7.12/tools/ch2py/main.cpp000066400000000000000000000045221476226660600171000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include "dpinyin.h" DCORE_USE_NAMESPACE int main(int argc, char **argv) { QCoreApplication a(argc, argv); a.setOrganizationName("deepin"); a.setApplicationName("ch2py"); a.setApplicationVersion("0.0.1"); QCommandLineParser cp; cp.setApplicationDescription("ch2py tool is a command tool that convert Chinese words to Pinyin.\n" "The commands of DCI tools can be expressed as follows:\n" "\t ch2py [chinese words]\n" "\t ch2py --tonestyle notones [chinese words]\n" "\t ch2py --letters [chinese words]\n" ); QCommandLineOption tonestyle = QCommandLineOption(QStringList() << "s" << "tonestyle", "tone style value can be \"notones\",\"tones\",\"numtones\"", "tonestyle", "tones"); QCommandLineOption letters = QCommandLineOption(QStringList() << "l" << "letters", "convert Chinese words to Pinyin first letters"); cp.addOption(tonestyle); cp.addOption(letters); cp.addPositionalArgument("words", "words to be converted to pinyin"); cp.addHelpOption(); cp.process(a); QString words = cp.positionalArguments().join(" "); if (words.isEmpty()) { cp.showHelp(); } QString tones = cp.value("tonestyle"); ToneStyle ts = TS_Tone; if (!tones.compare("notones")) ts = TS_NoneTone; else if (!tones.compare("numtones")) ts = TS_ToneNum; QElapsedTimer timer; timer.start(); qint64 size = -1; if (cp.isSet(letters)) { const auto &ls = firstLetters(words); printf("%s\n", qPrintable(ls.join("\n"))); size = ls.size(); } else { const auto &py = pinyin(words, ts); printf("%s\n", qPrintable(py.join("\n"))); size = py.size(); } std:: cout << "Total size: " << size << ", time:" << timer.elapsed() << " ms" << std::endl; return 0; } dtkcore-5.7.12/tools/dci/000077500000000000000000000000001476226660600151575ustar00rootroot00000000000000dtkcore-5.7.12/tools/dci/CMakeLists.txt000066400000000000000000000013151476226660600177170ustar00rootroot00000000000000set(TARGET_NAME dci) set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) add_definitions(-DDTK_NO_PROJECT) # start dci include(../../src/dci/dci.cmake) add_executable(${BIN_NAME} ${dci_SRCS} main.cpp ) target_link_libraries(${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::CorePrivate ) target_include_directories(${BIN_NAME} PUBLIC ../../include/ ../../include/dci/ ../../include/DtkCore/ ../../include/base/ ../../include/global/ ) set_target_properties(${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME}) #end dci install(TARGETS ${BIN_NAME} DESTINATION "${TOOL_INSTALL_DIR}") dtkcore-5.7.12/tools/dci/main.cpp000066400000000000000000000224561476226660600166200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include "dci/ddcifile.h" static QString getSymLinkTarget(const QString &file, const QString &originPath) { char target[512] = {0}; const auto ret = readlink(file.toLocal8Bit().constData(), target, 511); if (ret <= 0) return QString(); QString tar = QByteArray(target, ret); QString path = originPath; if (originPath.endsWith('/')) path = path.left(path.length() - 1); if (tar.startsWith(path)) { tar = tar.remove(0, path.length()); } return tar; } static bool copyFilesToDci(DDciFile *dci, const QString &targetDir, const QString &sourceDir, const QString &originPath) { QDir dir(sourceDir); for (const auto &info : dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)) { const QString &newFile = QDir(targetDir).filePath(info.fileName()); if (info.isDir()) { if (!dci->mkdir(newFile)) return false; if (!copyFilesToDci(dci, newFile, info.absoluteFilePath(), originPath)) return false; } else if (info.isSymLink()) { if (!dci->link(getSymLinkTarget(info.absoluteFilePath(), originPath), newFile)) return false; } else if (info.isFile()) { QFile file(info.absoluteFilePath()); if (!file.open(QIODevice::ReadOnly)) return false; if (!dci->writeFile(newFile, file.readAll())) return false; } } return true; } QString cleanPath(const QString &path) { return path.size() < 2 || !path.endsWith(QDir::separator()) ? path : path.chopped(1); } bool createTo(const QString &sourceDir, const QString &targetDir) { QFileInfo info(cleanPath(sourceDir)); if (!info.isDir()) return false; const QString &iconName = info.fileName(); if (iconName.isEmpty()) { printf("The icon name is not correctly resolved in the source path: \"%s\".\n", qPrintable(sourceDir)); return false; } const auto newFile = QDir(targetDir).filePath(iconName + ".dci"); if (QFile::exists(newFile)) { printf("The path \"%s\" already exists.\n", qPrintable(newFile)); return false; } DDciFile dci; if (!copyFilesToDci(&dci, "/", sourceDir, sourceDir)) return false; return dci.writeToFile(newFile); } static bool copyFilesFromDci(const DDciFile *dci, const QString &targetDir, const QString &sourceDir, QMap &pathMap) { QDir target(targetDir); for (const QString &file : dci->list(sourceDir)) { const QString &newFileName = QFileInfo(file).fileName(); const QString &newFilePath = target.filePath(newFileName); pathMap.insert(file, newFilePath); const auto &type = dci->type(file); if (type == DDciFile::Directory) { if (!target.mkdir(newFileName)) return false; if (!copyFilesFromDci(dci, newFilePath, file, pathMap)) return false; } else if (type == DDciFile::File) { QFile newFile(newFilePath); if (!newFile.open(QIODevice::WriteOnly)) return false; const auto &data = dci->dataRef(file); if (newFile.write(data) != data.size()) return false; } else if (type == DDciFile::Symlink) { // link the real source later } else { return false; } } return true; } bool exportTo(const QString &dciFile, const QString &targetDir) { QFileInfo info(dciFile); if (!info.isFile() || info.suffix() != "dci") return false; const QString &newDir = QDir(targetDir).filePath(info.baseName()); if (QDir(newDir).exists()) return false; if (!QDir::current().mkdir(newDir)) return false; DDciFile dci(dciFile); if (!dci.isValid()) return false; QMap pathMap; if (!copyFilesFromDci(&dci, QDir(newDir).absolutePath(), "/", pathMap)) return false; // link to real source for (auto it = pathMap.begin(); it != pathMap.end(); it++) { if (dci.type(it.key()) == DDciFile::Symlink) { const QString &realSource = it.value(); const QDir &dirInDci(QFileInfo(it.key()).path()); const QDir &dirRealSrc(QFileInfo(realSource).path()); const QString &target = dci.symlinkTarget(it.key(), true); const QString &absoluteTarget = QDir::cleanPath(dirInDci.absoluteFilePath(target)); const QString &realTarget = pathMap.value(absoluteTarget); // link to relative path(e.g. xx.webp -> ../../normal.light/x/xx.webp) if (!QFile::link(dirRealSrc.relativeFilePath(realTarget), realSource)) { qErrnoWarning(strerror(errno)); return false; } } } return true; } #define SPACE_CHAR " " #define BEGINE_CHAR "├── " #define MIDDLE_CHAR "│ " #define END_CHAR "└── " #define ARROW_CHAR " -> " static inline QString pathName(const QString &path) { QDir dir(path); return dir.dirName().isEmpty() ? path : dir.dirName(); } void print(DDciFile &dci, const QString &dir = QString("/"), QString prefix = QString()) { const auto &fileList = dci.list(dir); QString dirName = pathName(dir); printf("%s\n", qPrintable(prefix + dirName)); prefix.replace(END_CHAR, SPACE_CHAR); prefix.replace(BEGINE_CHAR, MIDDLE_CHAR); for (const auto &file : fileList) { QString newPrefix = prefix; newPrefix.append(file == fileList.last() ? END_CHAR : BEGINE_CHAR); if (dci.type(file) == DDciFile::Directory) { print(dci, file, newPrefix); } else { QString fileName = pathName(file); QString symlinkTarget; if (dci.type(file) == DDciFile::Symlink) { symlinkTarget.append(ARROW_CHAR).append(dci.symlinkTarget(file)); } printf("%s\n", qPrintable(newPrefix + fileName + symlinkTarget)); } } } bool tree(const QString &dciFile) { QFileInfo info(dciFile); DDciFile dci(dciFile); if (!dci.isValid()) return false; print(dci, "/"); return true; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setOrganizationName("zccrs"); a.setApplicationName("dci"); a.setApplicationVersion("0.0.1"); QCommandLineParser commandParser; commandParser.setApplicationDescription("DCI tool is a command tool that automatically packs and unpacks DCI directories.\n" "If you have created an icon directory according to the correct DCI directory specification,\n" "you can easily make the DCI icons with this tool.\n" "The commands of DCI tools can be expressed as follows:\n" "\t dci --create [target file path] [source directory path]\n" "\t dci --export [target directory path] [source file path]\n" "\t dci --tree [target file path]\n" "For example, the tool is used in the following ways: \n" "\t dci --create ~/Desktop ~/Desktop/action_add\n" "\t dci --export ~/Desktop ~/Desktop/action_add.dci\n" "\t dci --tree ~/Desktop/action_add.dci\n"); auto options = QList { QCommandLineOption("create", "Create the new dci files by the directorys", "targetDirectiry"), QCommandLineOption("export", "Export the dci files to the directorys", "targetDirectory"), QCommandLineOption("tree", "tree view the dci file", "targetDciFile"), }; commandParser.addOptions(options); commandParser.addPositionalArgument("sources", "The directorys of create or the dci files of export", "[dir1 dir2...]/[file1 file2...]"); commandParser.addHelpOption(); commandParser.addVersionOption(); commandParser.process(a); if (commandParser.isSet(options.at(0))) { for (const QString &dir : commandParser.positionalArguments()) { if (!createTo(dir, commandParser.value(options.at(0)))) { printf("Failed on create dci file for \"%s\"\n", qPrintable(dir)); } } } else if (commandParser.isSet(options.at(1))) { for (const QString &dci : commandParser.positionalArguments()) { if (!exportTo(dci, commandParser.value(options.at(1)))) { printf("Failed on export the \"%s\" dci file\n", qPrintable(dci)); } } } else if (commandParser.isSet(options.at(2))) { const QString &dci = commandParser.value(options.at(2)); if (!tree(dci)) { printf("Failed on view the \"%s\" dci file\n", qPrintable(dci)); } } else { commandParser.showHelp(-1); } return 0; } dtkcore-5.7.12/tools/dconfig2cpp/000077500000000000000000000000001476226660600166165ustar00rootroot00000000000000dtkcore-5.7.12/tools/dconfig2cpp/CMakeLists.txt000066400000000000000000000010041476226660600213510ustar00rootroot00000000000000set(TARGET_NAME dconfig2cpp) set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) add_executable(${BIN_NAME} main.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core ) set_target_properties( ${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME} EXPORT_NAME DConfig2Cpp ) install( TARGETS ${BIN_NAME} EXPORT Dtk${DTK_VERSION_MAJOR}ToolsTargets DESTINATION ${TOOL_INSTALL_DIR} ) dtkcore-5.7.12/tools/dconfig2cpp/main.cpp000066400000000000000000000601301476226660600202460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include static QString toUnicodeEscape(const QString& input) { QString result; for (QChar ch : input) { result += QString("\\u%1").arg(ch.unicode(), 4, 16, QChar('0')); } return result; } // Converts a QJsonValue to a corresponding C++ code representation static QString jsonValueToCppCode(const QJsonValue &value){ if (value.isBool()) { return value.toBool() ? QLatin1String("true") : QLatin1String("false"); } else if (value.isDouble()) { const auto variantValue = value.toVariant(); if (variantValue.userType() == QVariant(static_cast(1)).userType()) { return QString::number(value.toInt()); } else if (variantValue.userType() == QVariant(static_cast(1)).userType()) { return QString::number(variantValue.toLongLong()); } return QString::number(value.toDouble()); } else if (value.isString()) { const auto string = value.toString(); if (string.isEmpty()) { return QLatin1String("QLatin1String(\"\")"); } return QString("QStringLiteral(u\"%1\")").arg(toUnicodeEscape(string)); } else if (value.isNull()) { return "QVariant::fromValue(nullptr)"; } else if (value.isArray()) { QStringList elements; const auto array = value.toArray(); for (const QJsonValue &element : array) { elements << "QVariant(" + jsonValueToCppCode(element) + ")"; } return "QList{" + elements.join(", ") + "}"; } else if (value.isObject()) { QStringList elements; QJsonObject obj = value.toObject(); for (auto it = obj.begin(); it != obj.end(); ++it) { elements << QString("{QStringLiteral(u\"%1\"), QVariant(%2)}") .arg(toUnicodeEscape(it.key()), jsonValueToCppCode(it.value())); } return "QVariantMap{" + elements.join(", ") + "}"; } else { return "QVariant()"; } } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCommandLineParser parser; parser.setApplicationDescription(QLatin1String("DConfig to C++ class generator")); parser.addHelpOption(); // Define command line options QCommandLineOption classNameOption(QStringList() << QLatin1String("c") << QLatin1String("class-name"), QLatin1String("Name of the generated class"), QLatin1String("className")); parser.addOption(classNameOption); QCommandLineOption sourceFileOption(QStringList() << QLatin1String("o") << QLatin1String("output"), QLatin1String("Path to the output source(header only) file"), QLatin1String("sourceFile")); parser.addOption(sourceFileOption); QCommandLineOption forceRequestThread(QStringList() << QLatin1String("force-request-thread"), QLatin1String("Force request thread to create DConfig instance")); parser.addOption(forceRequestThread); QCommandLineOption noComment(QStringList() << QLatin1String("no-comment"), QLatin1String("Do not generate comments in the generated code")); parser.addOption(noComment); parser.addPositionalArgument(QLatin1String("json-file"), QLatin1String("Path to the input JSON file")); parser.process(app); const QStringList args = parser.positionalArguments(); if (args.size() != 1) { parser.showHelp(-1); } QString className = parser.value(classNameOption); const QString jsonFileName = QFileInfo(args.first()).completeBaseName(); if (className.isEmpty()) { className = QLatin1String("dconfig_") + QString(jsonFileName).replace('.', '_'); } QString sourceFilePath = parser.value(sourceFileOption); if (sourceFilePath.isEmpty()) { sourceFilePath = className.toLower() + QLatin1String(".hpp"); } QFile file(args.first()); if (!file.open(QIODevice::ReadOnly)) { qWarning() << QLatin1String("Failed to open file:") << args.first(); return -1; } QByteArray data = file.readAll(); QJsonDocument doc = QJsonDocument::fromJson(data); QJsonObject root = doc.object(); // Check magic value if (root[QLatin1String("magic")].toString() != QLatin1String("dsg.config.meta")) { qWarning() << QLatin1String("Invalid magic value in JSON file"); return -1; } // Generate header and source files QFile headerFile(sourceFilePath); if (!headerFile.open(QIODevice::WriteOnly | QIODevice::Text)) { qWarning() << QLatin1String("Failed to open file for writing:") << sourceFilePath; return -1; } QTextStream headerStream(&headerFile); // Extract version and add it as a comment in the generated code QString version = root[QLatin1String("version")].toString(); // Generate header and source file comments QString commandLineArgs = QCoreApplication::arguments().join(QLatin1String(" ")); QString generationTime = QDateTime::currentDateTime().toString(Qt::ISODate); if (!parser.isSet(noComment)) { QString headerComment = QString( "/**\n" " * This file is generated by dconfig2cpp.\n" " * Command line arguments: %1\n" " * Generation time: %2\n" " * JSON file version: %3\n" " *\n" " * WARNING: DO NOT MODIFY THIS FILE MANUALLY.\n" " * If you need to change the content, please modify the dconfig2cpp tool.\n" " */\n\n" ).arg(commandLineArgs, generationTime, version); headerStream << headerComment; } QJsonObject contents = root[QLatin1String("contents")].toObject(); // Write header file content headerStream << "#ifndef " << className.toUpper() << "_H\n"; headerStream << "#define " << className.toUpper() << "_H\n\n"; headerStream << "#include \n"; headerStream << "#include \n"; headerStream << "#include \n"; headerStream << "#include \n"; headerStream << "#include \n"; headerStream << "#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n" << "#include \n" << "#endif\n"; headerStream << "#include \n\n"; headerStream << "class " << className << " : public QObject {\n"; headerStream << " Q_OBJECT\n\n"; struct Property { QString typeName; QString propertyName; QString capitalizedPropertyName; QString propertyNameString; QJsonValue defaultValue; }; QList properties; QStringList propertyNames; QStringList propertyNameStrings; static QStringList usedKeywords = { className, "create", "createByName", "config", "keyList", "isInitializeSucceed", "isInitializeFailed", "isInitializing", "isDefaultValue", "m_config", "m_status", }; for (int i = 0; i <= (contents.size()) / 32; ++i) { usedKeywords << QLatin1String("m_propertySetStatus") + QString::number(i); } // Iterate over JSON contents to extract properties for (auto it = contents.begin(); it != contents.end(); ++it) { QJsonObject obj = it.value().toObject(); QString propertyName = it.key(); QString typeName; const auto value = obj[QLatin1String("value")]; if (value.isBool()) { typeName = "bool"; } else if (value.isArray()) { typeName = "QList"; } else if (value.isObject()) { typeName = "QVariantMap"; } else if (value.isDouble()) { const auto variantValue = value.toVariant(); typeName = QString::fromLatin1(variantValue.typeName()); } else if (value.isString()) { typeName = "QString"; } else { typeName = "QVariant"; } QString capitalizedPropertyName = propertyName; if (!capitalizedPropertyName.isEmpty() && capitalizedPropertyName[0].isLower()) { capitalizedPropertyName[0] = capitalizedPropertyName[0].toUpper(); } propertyNames << propertyName; properties.append(Property({ typeName, propertyName, capitalizedPropertyName, "QStringLiteral(\"" + propertyName + "\")", obj[QLatin1String("value")] })); propertyNameStrings << properties.last().propertyNameString; const QString readFunction = usedKeywords.contains(propertyName) ? QLatin1String(" READ get") + capitalizedPropertyName : QLatin1String(" READ ") + propertyName; headerStream << " Q_PROPERTY(" << typeName << " " << propertyName << readFunction << " WRITE set" << capitalizedPropertyName << " NOTIFY " << propertyName << "Changed" << " RESET reset" << capitalizedPropertyName << ")\n"; } headerStream << " Q_CLASSINFO(\"DConfigKeyList\", \"" << propertyNames.join(";") <<"\")\n" << " Q_CLASSINFO(\"DConfigFileName\", \"" << QString(jsonFileName).replace("\n", "\\n").replace("\r", "\\r") <<"\")\n" << " Q_CLASSINFO(\"DConfigFileVersion\", \"" << version <<"\")\n\n" << "public:\n" << " explicit " << className << R"((QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId, const QString &subpath, QObject *parent) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QLatin1String("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=, this]() { DTK_CORE_NAMESPACE::DConfig *config = nullptr; if (backend) { if (appId.isNull()) { config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); } else { config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); } } else { if (appId.isNull()) { config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); } else { config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); } } if (!config) { qWarning() << QLatin1String("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initializeInConfigThread(config); worker->deleteLater(); }); } )"; const QString jsonFileString = "QStringLiteral(u\"" + toUnicodeEscape(jsonFileName) + "\")"; // Generate constructors if (parser.isSet(forceRequestThread)) headerStream << " static " << className << "* create(QThread *thread, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n"; else headerStream << " static " << className << "* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; headerStream << " { return new " << className << "(thread, nullptr, " << jsonFileString << ", appId, subpath, parent); }\n"; if (parser.isSet(forceRequestThread)) headerStream << " static " << className << "* create(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n"; else headerStream << " static " << className << "* create(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; headerStream << " { return new " << className << "(thread, backend, " << jsonFileString << ", appId, subpath, parent); }\n"; if (parser.isSet(forceRequestThread)) headerStream << " static " << className << "* createByName(QThread *thread, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n"; else headerStream << " static " << className << "* createByName(const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; headerStream << " { return new " << className << "(thread, nullptr, name, appId, subpath, parent); }\n"; if (parser.isSet(forceRequestThread)) headerStream << " static " << className << "* createByName(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr)\n"; else headerStream << " static " << className << "* createByName(DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread())\n"; headerStream << " { return new " << className << "(thread, backend, name, appId, subpath, parent); }\n"; // Destructor headerStream << " ~" << className << R"(() { if (m_config.loadRelaxed()) { m_config.loadRelaxed()->deleteLater(); } } Q_INVOKABLE DTK_CORE_NAMESPACE::DConfig *config() const { return m_config.loadRelaxed(); } Q_INVOKABLE bool isInitializeSucceed() const { return m_status.loadRelaxed() == static_cast(Status::Succeed); } Q_INVOKABLE bool isInitializeFailed() const { return m_status.loadRelaxed() == static_cast(Status::Failed); } Q_INVOKABLE bool isInitializing() const { return m_status.loadRelaxed() == static_cast(Status::Invalid); } )"; headerStream << " Q_INVOKABLE QStringList keyList() const {\n" << " return { " << propertyNameStrings.join(",\n ") << "};\n" << " }\n\n"; headerStream << " Q_INVOKABLE bool isDefaultValue(const QString &key) const {\n"; for (int i = 0; i < properties.size(); ++i) { headerStream << " if (key == " << properties.at(i).propertyNameString << ")\n" << " return " << properties.at(i).propertyName << "IsDefaultValue();\n"; } headerStream << " return false;\n" << " }\n\n"; // Generate property getter and setter methods for (int i = 0; i < properties.size(); ++i) { const Property &property = properties[i]; const QString readFunction = usedKeywords.contains(property.propertyName) ? "get" + property.capitalizedPropertyName : property.propertyName; assert(!usedKeywords.contains(readFunction)); headerStream << " " << property.typeName << " " << readFunction << "() const {\n" << " return p_" << property.propertyName << ";\n }\n"; headerStream << " void set" << property.capitalizedPropertyName << "(const " << property.typeName << " &value) {\n" << " auto oldValue = p_" << property.propertyName << ";\n" << " p_" << property.propertyName << " = value;\n" << " markPropertySet(" << i << ");\n" << " if (auto config = m_config.loadRelaxed()) {\n" << " QMetaObject::invokeMethod(config, [this, value]() {\n" << " m_config.loadRelaxed()->setValue(" << property.propertyNameString << ", value);\n" << " });\n" << " }\n" << " if (p_" << property.propertyName << " != oldValue) {\n" << " Q_EMIT " << property.propertyName << "Changed();\n" << " Q_EMIT valueChanged(" << property.propertyNameString << ", value);\n" << " }\n" << " }\n" << " void reset" << property.capitalizedPropertyName << "() {\n" << " if (auto config = m_config.loadRelaxed()) {\n" << " QMetaObject::invokeMethod(config, [this]() {\n" << " m_config.loadRelaxed()->reset(" << property.propertyNameString << ");\n" << " });\n" << " }\n" << " }\n"; headerStream << "#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n"; headerStream << " QBindable<" << property.typeName << "> bindable" << property.capitalizedPropertyName << "() {\n" << " return QBindable<" << property.typeName << ">(this, " << property.propertyNameString << ");\n" << " }\n"; headerStream << "#endif\n"; headerStream << " Q_INVOKABLE bool " << property.propertyName << "IsDefaultValue() const {\n" << " return !testPropertySet(" << i << ");\n" << " }\n"; } // Generate signals for property changes headerStream << "Q_SIGNALS:\n" << " void configInitializeFailed(DTK_CORE_NAMESPACE::DConfig *config);\n" << " void configInitializeSucceed(DTK_CORE_NAMESPACE::DConfig *config);\n" << " void valueChanged(const QString &key, const QVariant &value);\n\n"; for (const Property &property : std::as_const(properties)) { headerStream << " void " << property.propertyName << "Changed();\n"; } // Generate private methods and members headerStream << "private:\n"; headerStream << " void initializeInConfigThread(DTK_CORE_NAMESPACE::DConfig *config) {\n" << " Q_ASSERT(!m_config.loadRelaxed());\n" << " m_config.storeRelaxed(config);\n" << " if (!config->isValid()) {\n" << " m_status.storeRelaxed(static_cast(Status::Failed));\n" << " Q_EMIT configInitializeFailed(config);\n" << " return;\n" << " }\n\n"; for (int i = 0; i < properties.size(); ++i) { const Property &property = properties[i]; headerStream << " if (testPropertySet(" << i << ")) {\n"; headerStream << " config->setValue(" << property.propertyNameString << ", QVariant::fromValue(p_" << property.propertyName << "));\n"; headerStream << " } else {\n"; headerStream << " updateValue(" << property.propertyNameString << ", QVariant::fromValue(p_" << property.propertyName << "));\n"; headerStream << " }\n"; } headerStream << R"( connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { updateValue(key); }, Qt::DirectConnection); m_status.storeRelaxed(static_cast(Status::Succeed)); Q_EMIT configInitializeSucceed(config); } void updateValue(const QString &key, const QVariant &fallback = QVariant()) { Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); const QVariant &value = m_config.loadRelaxed()->value(key, fallback); )"; for (int i = 0; i < properties.size(); ++i) { const Property &property = properties.at(i); headerStream << " if (key == " << property.propertyNameString << ") {\n"; headerStream << " markPropertySet(" << i << ", !m_config.loadRelaxed()->isDefaultValue(key));\n"; headerStream << " auto newValue = qvariant_cast<" << property.typeName << ">(value);\n" << " QMetaObject::invokeMethod(this, [this, newValue, key, value]() {\n" << " Q_ASSERT(QThread::currentThread() == this->thread());\n" << " if (p_" << property.propertyName << " != newValue) {\n" << " p_" << property.propertyName << " = newValue;\n" << " Q_EMIT " << property.propertyName << "Changed();\n" << " Q_EMIT valueChanged(key, value);\n" << " }\n" << " });\n" << " return;\n" << " }\n"; } headerStream << " }\n"; // Mark property as set headerStream << " inline void markPropertySet(const int index, bool on = true) {\n"; for (int i = 0; i <= (properties.size()) / 32; ++i) { headerStream << " if (index < " << (i + 1) * 32 << ") {\n" << " if (on)\n" << " m_propertySetStatus" << QString::number(i) << ".fetchAndOrOrdered(1 << (index - " << i * 32 << "));\n" << " else\n" << " m_propertySetStatus" << QString::number(i) << ".fetchAndAndOrdered(1 << (index - " << i * 32 << "));\n" << " return;\n" << " }\n"; } headerStream << " Q_UNREACHABLE();\n }\n"; // Test if property is set headerStream << " inline bool testPropertySet(const int index) const {\n"; for (int i = 0; i <= (properties.size()) / 32; ++i) { headerStream << " if (index < " << (i + 1) * 32 << ") {\n"; headerStream << " return (m_propertySetStatus" << QString::number(i) << ".loadRelaxed() & (1 << (index - " << i * 32 << ")));\n"; headerStream << " }\n"; } headerStream << " Q_UNREACHABLE();\n" << " }\n"; // Member variables headerStream << R"( QAtomicPointer m_config = nullptr; public: enum class Status { Invalid = 0, Succeed = 1, Failed = 2 }; private: QAtomicInteger m_status = static_cast(Status::Invalid); )"; // Property variables for (const Property &property : std::as_const(properties)) { if (property.typeName == QLatin1String("int") || property.typeName == QLatin1String("qint64")) { headerStream << " // Note: If you expect a double type, add 'e' to the number in the JSON value field, e.g., \"value\": 1.0e, not just 1.0\n"; } else if (property.typeName == QLatin1String("QString")) { headerStream << " // Default value: \"" << property.defaultValue.toString().replace("\n", "\\n").replace("\r", "\\r") << "\"\n"; } headerStream << " " << property.typeName << " p_" << property.propertyName << " { "; headerStream << jsonValueToCppCode(property.defaultValue) << " };\n"; } // Property set status variables for (int i = 0; i <= (properties.size()) / 32; ++i) { headerStream << " QAtomicInteger m_propertySetStatus" << QString::number(i) << " = 0;\n"; } headerStream << "};\n\n"; headerStream << "#endif // " << className.toUpper() << "_H\n"; return 0; } dtkcore-5.7.12/tools/deepin-os-release/000077500000000000000000000000001476226660600177215ustar00rootroot00000000000000dtkcore-5.7.12/tools/deepin-os-release/CMakeLists.txt000066400000000000000000000016711476226660600224660ustar00rootroot00000000000000set(TARGET_NAME deepin-os-release) set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_AUTOMOC ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) add_definitions(-DDTK_NO_PROJECT) # start dci set(dci_SRCS ../../include/global/dsysinfo.h ../../include/global/ddesktopentry.h ../../src/dsysinfo.cpp ../../src/ddesktopentry.cpp ) add_executable(${BIN_NAME} ${dci_SRCS} main.cpp ) target_compile_definitions(${BIN_NAME} PUBLIC DSYSINFO_PREFIX="${DSYSINFO_PREFIX}") target_link_libraries(${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::CorePrivate ) target_include_directories(${BIN_NAME} PUBLIC ../../include/ ../../include/dci/ ../../include/DtkCore/ ../../include/base/ ../../include/global/ ) set_target_properties(${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME}) install(TARGETS ${BIN_NAME} DESTINATION "${TOOL_INSTALL_DIR}") #end dci dtkcore-5.7.12/tools/deepin-os-release/main.cpp000066400000000000000000000145251476226660600213600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsysinfo.h" #include #include #include #include #include #include DCORE_USE_NAMESPACE bool distributionInfoValid() { return QFile::exists(DSysInfo::distributionInfoPath()); } void printDistributionOrgInfo(DSysInfo::OrgType type) { QString sectionName = DSysInfo::distributionInfoSectionName(type); printf("%s Name: %s\n", qPrintable(sectionName), qPrintable(DSysInfo::distributionOrgName(type))); printf("%s Logo (Normal size): %s\n", qPrintable(sectionName), qPrintable(DSysInfo::distributionOrgLogo(type))); printf("%s Website: %s\n", qPrintable(sectionName), qPrintable(DSysInfo::distributionOrgWebsite(type).second)); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Q_UNUSED(app) QCommandLineParser parser; QCommandLineOption option_all("all", "Print All Information"); QCommandLineOption option_deepin_type("deepin-type", " "); QCommandLineOption option_deepin_version("deepin-version", " "); QCommandLineOption option_deepin_edition("deepin-edition", " "); QCommandLineOption option_deepin_copyright("deepin-copyright", " "); QCommandLineOption option_product_type("product-type", " "); QCommandLineOption option_product_version("product-version", " "); QCommandLineOption option_computer_name("computer-name", "Computer Name"); QCommandLineOption option_cpu_model("cpu-model", "CPU Model"); QCommandLineOption option_installed_memory_size("installed-memory-size", "Installed Memory Size (GiB)"); QCommandLineOption option_memory_size("memory-size", "Memory Size (GiB)"); QCommandLineOption option_disk_size("disk-size", "Disk Size (GiB)"); QCommandLineOption option_distribution_info("distribution-info", "Distribution information"); QCommandLineOption option_distributer_info("distributer-info", "Distributer information"); parser.addOptions({option_all, option_deepin_type, option_deepin_version, option_deepin_edition, option_deepin_copyright, option_product_type, option_product_version, option_computer_name, option_cpu_model, option_installed_memory_size, option_memory_size, option_disk_size, option_distribution_info, option_distributer_info}); parser.addHelpOption(); parser.addVersionOption(); parser.process(app); if (argc < 2) parser.showHelp(); if (parser.isSet(option_all)) { printf("Computer Name: %s\n", qPrintable(DSysInfo::computerName())); printf("CPU Model: %s x %d\n", qPrintable(DSysInfo::cpuModelName()), QThread::idealThreadCount()); printf("Installed Memory Size: %f GiB\n", DSysInfo::memoryInstalledSize() / 1024.0 / 1024 / 1024); printf("Memory Size: %f GiB\n", DSysInfo::memoryTotalSize() / 1024.0 / 1024 / 1024); printf("Disk Size: %f GiB\n", DSysInfo::systemDiskSize() / 1024.0 / 1024 / 1024); if (DSysInfo::isDeepin() && DSysInfo::isDDE()) { printf("Deepin Type: %s\n", qPrintable(DSysInfo::deepinTypeDisplayName())); printf("Deepin Version: %s\n", qPrintable(DSysInfo::deepinVersion())); if (!DSysInfo::deepinEdition().isEmpty()) printf("Deepin Edition: %s\n", qPrintable(DSysInfo::deepinEdition())); if (!DSysInfo::deepinCopyright().isEmpty()) printf("Deepin Copyright: %s\n", qPrintable(DSysInfo::deepinCopyright())); } printf("Operating System Name: %s\n", qPrintable(DSysInfo::operatingSystemName())); printf("Product Type: %s\n", qPrintable(DSysInfo::productTypeString())); printf("Product Version: %s\n", qPrintable(DSysInfo::productVersion())); if (DSysInfo::isDeepin()) { printf("Uos Product Name: %s\n", qPrintable(DSysInfo::uosProductTypeName())); printf("Uos SystemName Name: %s\n", qPrintable(DSysInfo::uosSystemName())); printf("Uos Edition Name: %s\n", qPrintable(DSysInfo::uosEditionName())); printf("Uos SP Version: %s\n", qPrintable(DSysInfo::spVersion())); printf("Uos update Version: %s\n", qPrintable(DSysInfo::udpateVersion())); printf("Uos major Version: %s\n", qPrintable(DSysInfo::majorVersion())); printf("Uos minor Version: %s\n", qPrintable(DSysInfo::minorVersion())); printf("Uos build Version: %s\n", qPrintable(DSysInfo::buildVersion())); } if (distributionInfoValid()) { printDistributionOrgInfo(DSysInfo::Distribution); printDistributionOrgInfo(DSysInfo::Distributor); } } else { if (parser.isSet(option_deepin_type)) printf("%s", qPrintable(DSysInfo::uosEditionName(QLocale::c()))); else if (parser.isSet(option_deepin_version)) printf("%s", qPrintable(DSysInfo::majorVersion())); else if (parser.isSet(option_deepin_edition)) printf("%s", qPrintable(DSysInfo::deepinEdition())); else if (parser.isSet(option_deepin_copyright)) printf("%s", qPrintable(DSysInfo::deepinCopyright())); else if (parser.isSet(option_product_type)) printf("%s", qPrintable(DSysInfo::productTypeString())); else if (parser.isSet(option_product_version)) printf("%s", qPrintable(DSysInfo::productVersion())); else if (parser.isSet(option_cpu_model)) printf("%s x %d", qPrintable(DSysInfo::cpuModelName()), QThread::idealThreadCount()); else if (parser.isSet(option_computer_name)) printf("%s", qPrintable(DSysInfo::computerName())); else if (parser.isSet(option_installed_memory_size)) printf("%f", DSysInfo::memoryInstalledSize() / 1024.0 / 1024 / 1024); else if (parser.isSet(option_memory_size)) printf("%f", DSysInfo::memoryTotalSize() / 1024.0 / 1024 / 1024); else if (parser.isSet(option_disk_size)) printf("%f", DSysInfo::systemDiskSize() / 1024.0 / 1024 / 1024); else if (parser.isSet(option_distribution_info)) { printDistributionOrgInfo(DSysInfo::Distribution); } else if (parser.isSet(option_distributer_info)) { printDistributionOrgInfo(DSysInfo::Distributor); } } return 0; } dtkcore-5.7.12/tools/qdbusxml2cpp/000077500000000000000000000000001476226660600170445ustar00rootroot00000000000000dtkcore-5.7.12/tools/qdbusxml2cpp/CMakeLists.txt000066400000000000000000000015501476226660600216050ustar00rootroot00000000000000set(TARGET_NAME qdbusxml2cpp-fix) set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus) add_executable(${BIN_NAME} qdbusxml2cpp.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::DBusPrivate ) set_target_properties( ${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME} EXPORT_NAME Xml2Cpp ) install( TARGETS ${BIN_NAME} EXPORT Dtk${DTK_VERSION_MAJOR}ToolsTargets DESTINATION ${TOOL_INSTALL_DIR} ) install( EXPORT Dtk${DTK_VERSION_MAJOR}ToolsTargets FILE Dtk${DTK_VERSION_MAJOR}ToolsTargets.cmake NAMESPACE Dtk${DTK_VERSION_MAJOR}:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools" ) dtkcore-5.7.12/tools/qdbusxml2cpp/README000066400000000000000000000001551476226660600177250ustar00rootroot00000000000000This is a modified version of the offficial qdbusxml2cpp, born with the support of property changed signals. dtkcore-5.7.12/tools/qdbusxml2cpp/qdbusxml2cpp.cpp000066400000000000000000001451761476226660600222120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PROGRAMNAME "qdbusxml2cpp-fix" #define PROGRAMVERSION "0.8" #define PROGRAMCOPYRIGHT "Copyright (C) 2016 Deepin Technology Co., Ltd." #define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" #if QT_VERSION >= QT_VERSION_CHECK(5,15,0) #define endl Qt::endl #else #define endl endl #endif static QString globalClassName; static QString parentClassName; static QString proxyFile; static QString adaptorFile; static QString inputFile; static bool skipNamespaces; static bool verbose; static bool includeMocs; static bool skipIncludeAnnotations; static QString commandLine; static QStringList includes; static QStringList wantedInterfaces; static const char help[] = "Usage: " PROGRAMNAME " [options...] [xml-or-xml-file] [interfaces...]\n" "Produces the C++ code to implement the interfaces defined in the input file.\n" "\n" "Options:\n" " -a Write the adaptor code to \n" " -c Use as the class name for the generated classes\n" " -h Show this information\n" " -i Add #include to the output\n" " -l When generating an adaptor, use as the parent class\n" " -m Generate #include \"filename.moc\" statements in the .cpp files\n" " -N Don't use namespaces\n" " -p Write the proxy code to \n" " -v Be verbose.\n" " -S Skip include annotation headers from \"types/\".\n" " -V Show the program version and quit.\n" "\n" "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" "program will automatically append the suffixes and produce both files.\n" "You can also use a colon (:) to separate the header name from the source file\n" "name, as in '-a filename_p.h:filename.cpp'.\n" "\n" "If you pass a dash (-) as the argument to either -p or -a, the output is written\n" "to the standard output\n"; static const char includeList[] = "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "#include \n" "\n" "#include \n"; static const char forwardDeclarations[] = "QT_BEGIN_NAMESPACE\n" "class QByteArray;\n" "template class QList;\n" "template class QMap;\n" "class QString;\n" "class QStringList;\n" "class QVariant;\n" "QT_END_NAMESPACE\n"; static void showHelp() { printf("%s", help); exit(0); } static void showVersion() { printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION); printf("D-Bus binding tool for Qt\n"); exit(0); } static QString nextArg(QStringList &args, int i, char opt) { QString arg = args.value(i); if (arg.isEmpty()) { printf("-%c needs at least one argument\n", opt); exit(1); } return args.takeAt(i); } static void parseCmdLine(QStringList args) { args.takeFirst(); commandLine = QLatin1String(PROGRAMNAME " "); commandLine += args.join(QLatin1Char(' ')); int i = 0; while (i < args.count()) { if (!args.at(i).startsWith(QLatin1Char('-'))) { ++i; continue; } QString arg = args.takeAt(i); char c = '\0'; if (arg.length() == 2) c = arg.at(1).toLatin1(); else if (arg == QLatin1String("--help")) c = 'h'; switch (c) { case 'a': adaptorFile = nextArg(args, i, 'a'); break; case 'c': globalClassName = nextArg(args, i, 'c'); break; case 'v': verbose = true; break; case 'i': includes << nextArg(args, i, 'i'); break; case 'l': parentClassName = nextArg(args, i, 'l'); break; case 'm': includeMocs = true; break; case 'N': skipNamespaces = true; break; case 'S': skipIncludeAnnotations = true; break; case '?': case 'h': showHelp(); break; case 'V': showVersion(); break; case 'p': proxyFile = nextArg(args, i, 'p'); break; default: printf("unknown option: '%s'\n", qPrintable(arg)); exit(1); } } if (!args.isEmpty()) inputFile = args.takeFirst(); wantedInterfaces << args; } static QDBusIntrospection::Interfaces readInput() { QFile input(inputFile); if (inputFile.isEmpty() || inputFile == QLatin1String("-")) { input.open(stdin, QIODevice::ReadOnly); } else { input.open(QIODevice::ReadOnly); } QByteArray data = input.readAll(); // check if the input is already XML data = data.trimmed(); if (data.startsWith("= QT_VERSION_CHECK(6, 0, 0) retval = QString("moc_%1cpp").arg(retval); #else retval += QLatin1String("moc"); #endif return retval; } static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost) { ts << "/*" << endl << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << endl << " * Command line was: " << commandLine << endl << " *" << endl << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << endl << " *" << endl << " * This is an auto-generated file." << endl; if (changesWillBeLost) ts << " * Do not edit! All changes made to it will be lost." << endl; else ts << " * This file may have been hand-edited. Look for HAND-EDIT comments" << endl << " * before re-generating it." << endl; ts << " */" << endl << endl; return ts; } enum ClassType { Proxy, Adaptor }; static QString classNameForInterface(const QString &interface, ClassType classType) { if (!globalClassName.isEmpty()) return globalClassName; QStringList parts = interface.split(QLatin1Char('.')); QString retval; if (classType == Proxy) foreach (QString part, parts) { part[0] = part[0].toUpper(); retval += part; } else { retval = parts.last(); retval[0] = retval[0].toUpper(); } if (classType == Proxy) retval += QLatin1String("Interface"); else retval += QLatin1String("Adaptor"); return retval; } static QString annotationValue(QDBusIntrospection::Annotations annotations, const QString &name) { #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) return annotations.value(name).value; #else return annotations.value(name); #endif } static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection::Annotations &annotations, int paramId = -1, const char *direction = "Out") { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) const auto& type = QDBusMetaType::signatureToMetaType(signature.toLatin1()); if (type.id() == QMetaType::Type::UnknownType) { #else int type = QDBusMetaType::signatureToType(signature.toLatin1()); if (type == QVariant::Invalid) { #endif QString annotationName = QString::fromLatin1("org.qtproject.QtDBus.QtTypeName"); if (paramId >= 0) annotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId); QString qttype = annotationValue(annotations, annotationName); if (!qttype.isEmpty()) return qttype.toLatin1(); QString oldAnnotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName"); if (paramId >= 0) oldAnnotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId); qttype = annotationValue(annotations, oldAnnotationName); if (qttype.isEmpty()) { fprintf(stderr, "Got unknown type `%s'\n", qPrintable(signature)); fprintf(stderr, "You should add \"/> to the XML description\n", qPrintable(annotationName)); exit(1); } fprintf(stderr, "Warning: deprecated annotation '%s' found; suggest updating to '%s'\n", qPrintable(oldAnnotationName), qPrintable(annotationName)); return qttype.toLatin1(); } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return type.name(); #else return QVariant::typeToName(QVariant::Type(type)); #endif } static QString nonConstRefArg(const QByteArray &arg) { return QLatin1String(arg + " &"); } static QString templateArg(const QByteArray &arg) { if (!arg.endsWith('>')) return QLatin1String(arg); return QLatin1String(arg + ' '); } static QString constRefArg(const QByteArray &arg) { if (!arg.startsWith('Q')) return QLatin1String(arg + ' '); else return QString(QLatin1String("const %1 &")).arg(QLatin1String(arg)); } static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) { QStringList retval; const int numInputArgs = inputArgs.count(); const int numOutputArgs = outputArgs.count(); retval.reserve(numInputArgs + numOutputArgs); for (int i = 0; i < numInputArgs; ++i) { const QDBusIntrospection::Argument &arg = inputArgs.at(i); QString name = arg.name; if (name.isEmpty()) name = QString(QLatin1String("in%1")).arg(i); else name.replace(QLatin1Char('-'), QLatin1Char('_')); while (retval.contains(name)) name += QLatin1String("_"); retval << name; } for (int i = 0; i < numOutputArgs; ++i) { const QDBusIntrospection::Argument &arg = outputArgs.at(i); QString name = arg.name; if (name.isEmpty()) name = QString(QLatin1String("out%1")).arg(i); else name.replace(QLatin1Char('-'), QLatin1Char('_')); while (retval.contains(name)) name += QLatin1String("_"); retval << name; } return retval; } static void writeArgList(QTextStream &ts, const QStringList &argNames, const QDBusIntrospection::Annotations &annotations, const QDBusIntrospection::Arguments &inputArgs, const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) { // input args: bool first = true; int argPos = 0; for (int i = 0; i < inputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = inputArgs.at(i); QString type = constRefArg(qtTypeName(arg.type, annotations, i, "In")); if (!first) ts << ", "; ts << type << argNames.at(argPos++); first = false; } argPos++; // output args // yes, starting from 1 for (int i = 1; i < outputArgs.count(); ++i) { const QDBusIntrospection::Argument &arg = outputArgs.at(i); QString name = arg.name; if (!first) ts << ", "; ts << nonConstRefArg(qtTypeName(arg.type, annotations, i, "Out")) << argNames.at(argPos++); first = false; } } static QString propertyGetter(const QDBusIntrospection::Property &property) { QString getter = annotationValue(property.annotations, "org.qtproject.QtDBus.PropertyGetter"); if (!getter.isEmpty()) return getter; getter = annotationValue(property.annotations, "com.trolltech.QtDBus.propertyGetter"); if (!getter.isEmpty()) { fprintf(stderr, "Warning: deprecated annotation 'com.trolltech.QtDBus.propertyGetter' found;" " suggest updating to 'org.qtproject.QtDBus.PropertyGetter'\n"); return getter; } getter = property.name; getter[0] = getter[0].toLower(); return getter; } static QString propertySetter(const QDBusIntrospection::Property &property) { QString setter = annotationValue(property.annotations, "org.qtproject.QtDBus.PropertySetter"); if (!setter.isEmpty()) return setter; setter = annotationValue(property.annotations, "com.trolltech.QtDBus.propertySetter"); if (!setter.isEmpty()) { fprintf(stderr, "Warning: deprecated annotation 'com.trolltech.QtDBus.propertySetter' found;" " suggest updating to 'org.qtproject.QtDBus.PropertySetter'\n"); return setter; } setter = QLatin1String("set") + property.name; setter[3] = setter[3].toUpper(); return setter; } static QString propertyNotifier(const QDBusIntrospection::Property &property) { QString notifier = annotationValue(property.annotations, "org.qtproject.QtDBus.PropertyNotifier"); if (!notifier.isEmpty()) return notifier; notifier = property.name + QLatin1String("Changed"); notifier[0] = notifier[0].toUpper(); return notifier; } static QString methodName(const QDBusIntrospection::Method &method) { QString name = annotationValue(method.annotations, "org.qtproject.QtDBus.MethodName"); if (!name.isEmpty()) return name; return method.name; } static QString stringify(const QString &data) { QString retval; int i; for (i = 0; i < data.length(); ++i) { retval += QLatin1Char('\"'); for (; i < data.length() && data[i] != QLatin1Char('\n') && data[i] != QLatin1Char('\r'); ++i) if (data[i] == QLatin1Char('\"')) retval += QLatin1String("\\\""); else retval += data[i]; if (i + 1 < data.length() && data[i] == QLatin1Char('\r') && data[i + 1] == QLatin1Char('\n')) i++; retval += QLatin1String("\\n\"\n"); } return retval; } static bool openFile(const QString &fileName, QFile &file) { if (fileName.isEmpty()) return false; bool isOk = false; if (fileName == QLatin1String("-")) { isOk = file.open(stdout, QIODevice::WriteOnly | QIODevice::Text); } else { file.setFileName(fileName); isOk = file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); } if (!isOk) fprintf(stderr, "Unable to open '%s': %s\n", qPrintable(fileName), qPrintable(file.errorString())); return isOk; } static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) { // open the file QString headerName = header(filename); QByteArray headerData; QTextStream hs(&headerData); QString cppName = cpp(filename); QByteArray cppData; QTextStream cs(&cppData); // write the header: writeHeader(hs, true); if (cppName != headerName) writeHeader(cs, false); // include guards: QString includeGuard; if (!headerName.isEmpty() && headerName != QLatin1String("-")) { includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_')); int pos = includeGuard.lastIndexOf(QLatin1Char('/')); if (pos != -1) includeGuard = includeGuard.mid(pos + 1); } else { includeGuard = QLatin1String("QDBUSXML2CPP_PROXY"); } includeGuard = QString(QLatin1String("%1")) .arg(includeGuard); hs << "#ifndef " << includeGuard << endl << "#define " << includeGuard << endl << endl; // include our stuff: hs << "#include " << endl << includeList << "#include " << endl; foreach (const QString &include, includes) { hs << "#include \"" << include << "\"" << endl; if (headerName.isEmpty()) cs << "#include \"" << include << "\"" << endl; } hs << endl; if (cppName != headerName) { if (!headerName.isEmpty() && headerName != QLatin1String("-")) cs << "#include \"" << headerName << "\"" << endl << endl; } QSet annotations; for (const QDBusIntrospection::Interface *interface : interfaces) { for (const auto &method : interface->methods) { for (int i(0); i != method.outputArgs.size(); ++i) { const QDBusIntrospection::Argument &arg = method.outputArgs[i]; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) if (QDBusMetaType::signatureToMetaType(arg.type.toLatin1()).id() != QMetaType::Type::UnknownType) #else if (QDBusMetaType::signatureToType(arg.type.toLatin1()) != QVariant::Invalid) #endif continue; annotations << qtTypeName(arg.type, method.annotations, i, "Out"); } for (int i(0); i != method.inputArgs.size(); ++i) { const QDBusIntrospection::Argument &arg = method.inputArgs[i]; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) if (QDBusMetaType::signatureToMetaType(arg.type.toLatin1()).id() != QMetaType::Type::UnknownType) #else if (QDBusMetaType::signatureToType(arg.type.toLatin1()) != QVariant::Invalid) #endif continue; annotations << qtTypeName(arg.type, method.annotations, i, "In"); } } for (const auto &property : interface->properties) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) if (QDBusMetaType::signatureToMetaType(property.type.toLatin1()).id() != QMetaType::Type::UnknownType) #else if (QDBusMetaType::signatureToType(property.type.toLatin1()) != QVariant::Invalid) #endif continue; annotations << qtTypeName(property.type, property.annotations); } } if (!skipIncludeAnnotations) { for (const QString &annotation : annotations) { if (annotation.indexOf('<') == -1) { hs << "#include \"types/" << annotation.toLower() << ".h\"" << endl; } } } hs << endl; foreach (const QDBusIntrospection::Interface *interface, interfaces) { QString className = "__" + classNameForInterface(interface->name, Proxy); // using namespace Dtk::Core in cpp cs << "DCORE_USE_NAMESPACE" << endl; // comment: hs << "/*" << endl << " * Proxy class for interface " << interface->name << endl << " */" << endl; cs << "/*" << endl << " * Implementation of interface class " << className << endl << " */" << endl << endl; // private class declare hs << "class " << className << "Private;" << endl; // class header: add Dtk::Core hs << "class " << className << " : public DTK_CORE_NAMESPACE::DDBusExtendedAbstractInterface" << endl << "{" << endl << " Q_OBJECT" << endl; hs << endl; // private class defines cs << "class " << className << "Private" << endl << "{" << endl << "public:" << endl << " " << className << "Private() = default;" << endl << endl; // private class member cs << " // begin member variables" << endl; for (const auto &property : interface->properties) { QByteArray type = qtTypeName(property.type, property.annotations); cs << " " << type << " " << property.name << ';' << endl; } cs << endl; // stuffs member cs << "public:" << endl << " QMap m_processingCalls;" << endl << " QMap> m_waittingCalls;" << endl; cs << "};" << endl << endl; // end of private class defines // the interface name hs << "public:" << endl << " static inline const char *staticInterfaceName()" << endl << " { return \"" << interface->name << "\"; }" << endl << endl; // constructors/destructors: hs << "public:" << endl << " explicit " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);" << endl << endl << " ~" << className << "();" << endl << endl; cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)" << endl << " : DDBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent)" << endl << " , d_ptr(new " << className << "Private)" << endl << "{" << endl; if (!interface->properties.isEmpty()) cs << " connect(this, &" << className << "::propertyChanged, this, &" << className << "::onPropertyChanged);" << endl << endl; for (const QString &annotation : annotations) { if (annotation.indexOf('<') != -1) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) cs << " if (QMetaType::fromName(\"" << annotation << "\").id() == QMetaType::UnknownType) {" << endl; #else cs << " if (QMetaType::type(\"" << annotation << "\") == QMetaType::UnknownType) {" << endl; #endif cs << " qRegisterMetaType< " << annotation << " >(\"" << annotation << "\");" << endl; cs << " qDBusRegisterMetaType< " << annotation << " >();" << endl; cs << " }" << endl; } else { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) cs << " if (QMetaType::fromName(\"" << annotation << "\").id() == QMetaType::UnknownType)" << endl; #else cs << " if (QMetaType::type(\"" << annotation << "\") == QMetaType::UnknownType)" << endl; #endif cs << " register" << annotation << "MetaType();" << endl; } } cs << "}" << endl << endl << className << "::~" << className << "()" << endl << "{" << endl << " qDeleteAll(d_ptr->m_processingCalls.values());" << endl << " delete d_ptr;" << endl << "}" << endl << endl; if (!interface->properties.isEmpty()) { // onPropertyChanged cs << "void " << className << "::onPropertyChanged(const QString &propName, const QVariant &value)" << endl; cs << "{" << endl; for (const auto &property : interface->properties) { char first = property.name[0].toLatin1(); QString name = property.name; name[0] = QChar(first & ~0x20); QByteArray type = qtTypeName(property.type, property.annotations); cs << " if (propName == QStringLiteral(\"" << property.name << "\"))" << endl; cs << " {" << endl; cs << " const " << type << " &" << property.name << " = qvariant_cast<" << type << ">(value);" << endl; cs << " " << "if (d_ptr->" << property.name << " != " << property.name << ")" << endl; cs << " {" << endl; cs << " d_ptr->" << property.name << " = " << property.name << ';' << endl; cs << " Q_EMIT " << name << "Changed(d_ptr->" << property.name << ");" << endl; cs << " }" << endl; cs << " return;" << endl; cs << " }" << endl; cs << endl; } cs << " qWarning() << \"property not handle: \" << propName;" << endl; cs << " return;" << endl; cs << "}" << endl << endl; } // properties: foreach (const QDBusIntrospection::Property &property, interface->properties) { QByteArray type = qtTypeName(property.type, property.annotations); // QString templateType = templateArg(type); // QString constRefType = constRefArg(type); QString getter = propertyGetter(property); QString setter = propertySetter(property); QString notifier = propertyNotifier(property); hs << " Q_PROPERTY(" << type << " " << property.name; // getter: if (property.access != QDBusIntrospection::Property::Write) // it's readble hs << " READ " << getter; // setter if (property.access != QDBusIntrospection::Property::Read) // it's writeable hs << " WRITE " << setter; //notifier hs << " NOTIFY " << notifier; hs << ")" << endl; // getter: if (property.access != QDBusIntrospection::Property::Write) { // getter declare hs << " " << type << " " << getter << "();" << endl; // getter define cs << type << " " << className << "::" << getter << "()" << endl << "{" << endl << " return qvariant_cast<" << type << ">(internalPropGet(\"" << property.name << "\", &d_ptr->" << property.name << "));" << endl << "}" << endl << endl; } // setter: if (property.access != QDBusIntrospection::Property::Read) { // setter declare hs << " void " << setter << "(" << constRefArg(type) << "value);" << endl; // setter define cs << "void " << className << "::" << setter << "(" << constRefArg(type) << "value)" << endl << "{" << endl << endl << " internalPropSet(\"" << property.name << "\", QVariant::fromValue(value), &d_ptr->" << property.name << ");" << endl << "}" << endl << endl; } hs << endl; } // methods: hs << "public Q_SLOTS: // METHODS" << endl; foreach (const QDBusIntrospection::Method &method, interface->methods) { bool isDeprecated = annotationValue(method.annotations, "org.freedesktop.DBus.Deprecated") == QLatin1String("true"); bool isNoReply = annotationValue(method.annotations, QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"); if (isNoReply && !method.outputArgs.isEmpty()) { fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n", qPrintable(method.name), qPrintable(interface->name)); continue; } hs << " inline " << (isDeprecated ? "Q_DECL_DEPRECATED " : ""); if (isNoReply) { hs << "Q_NOREPLY void "; } else { hs << "QDBusPendingReply<"; for (int i = 0; i < method.outputArgs.count(); ++i) hs << (i > 0 ? ", " : "") << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out")); hs << "> "; } hs << methodName(method) << "("; QStringList argNames = makeArgNames(method.inputArgs); writeArgList(hs, argNames, method.annotations, method.inputArgs); hs << ")" << endl << " {" << endl << " QList argumentList;" << endl; if (!method.inputArgs.isEmpty()) { hs << " argumentList"; for (int argPos = 0; argPos < method.inputArgs.count(); ++argPos) hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; hs << ";" << endl; } if (isNoReply) hs << " callWithArgumentList(QDBus::NoBlock, " << "QStringLiteral(\"" << method.name << "\"), argumentList);" << endl; else hs << " return asyncCallWithArgumentList(QStringLiteral(\"" << method.name << "\"), argumentList);" << endl; // close the function: hs << " }" << endl; hs << endl; // queued version for void return type functions if (method.outputArgs.count() == 0) { hs << " inline void " << method.name << "Queued("; writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); hs << ")" << endl << " {" << endl << " QList argumentList;" << endl; int argPos = 0; if (!method.inputArgs.isEmpty()) { hs << " argumentList"; for (argPos = 0; argPos < method.inputArgs.count(); ++argPos) hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; hs << ";" << endl; } hs << endl << " CallQueued(" << "QStringLiteral(\"" << method.name << "\"), argumentList);" << endl << " }" << endl; } hs << endl; if (method.outputArgs.count() > 1) { const auto templateArgument = templateArg(qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out")); // generate the old-form QDBusReply methods with multiple incoming parameters hs << " inline " << (isDeprecated ? "Q_DECL_DEPRECATED " : "") << "QDBusReply<" << templateArgument << "> "; hs << method.name << "("; QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); hs << ")" << endl << " {" << endl << " QList argumentList;" << endl; int argPos = 0; if (!method.inputArgs.isEmpty()) { hs << " argumentList"; for (argPos = 0; argPos < method.inputArgs.count(); ++argPos) hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; hs << ";" << endl; } hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, " << "QStringLiteral(\"" << method.name << "\"), argumentList);" << endl; argPos++; hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == " << method.outputArgs.count() << ") {" << endl; // yes, starting from 1 for (int i = 1; i < method.outputArgs.count(); ++i) hs << " " << argNames.at(argPos++) << " = qdbus_cast<" << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out")) << ">(reply.arguments().at(" << i << "));" << endl; hs << " }" << endl << " return reply;" << endl << " }" << endl; } hs << endl; } hs << endl; hs << "Q_SIGNALS: // SIGNALS" << endl; foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { hs << " "; if (annotationValue(signal.annotations, QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true")) hs << "Q_DECL_DEPRECATED "; hs << "void " << signal.name << "("; QStringList argNames = makeArgNames(signal.outputArgs); writeArgList(hs, argNames, signal.annotations, signal.outputArgs); hs << ");" << endl; // finished for header } //propery changed signals hs << " // begin property changed signals" << endl; foreach (const QDBusIntrospection::Property &property, interface->properties) { hs << " "; QByteArray type = qtTypeName(property.type, property.annotations); QString constRefType = constRefArg(type); QString notifier = propertyNotifier(property); //notifier hs << "void " << notifier << "(" << constRefType << " value" << ") const;" << endl; } hs << endl; // queued stuffs hs << "public Q_SLOTS:" << endl << " void CallQueued(const QString &callName, const QList &args);" << endl << endl; cs << "void " << className << "::CallQueued(const QString &callName, const QList &args)" << endl << "{" << endl << " if (d_ptr->m_waittingCalls.contains(callName))" << endl << " {" << endl << " d_ptr->m_waittingCalls[callName] = args;" << endl << " return;" << endl << " }" << endl << " if (d_ptr->m_processingCalls.contains(callName))" << endl << " {" << endl << " d_ptr->m_waittingCalls.insert(callName, args);" << endl << " } else {" << endl << " QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args));" << endl << " connect(watcher, &QDBusPendingCallWatcher::finished, this, &" << className << "::onPendingCallFinished);" << endl << " d_ptr->m_processingCalls.insert(callName, watcher);" << endl << " }" << endl << "}" << endl << endl; hs << "private Q_SLOTS:" << endl << " void onPendingCallFinished(QDBusPendingCallWatcher *w);" << endl; if (!interface->properties.isEmpty()) hs << " void onPropertyChanged(const QString &propName, const QVariant &value);" << endl; hs << endl; cs << "void " << className << "::onPendingCallFinished(QDBusPendingCallWatcher *w)" << endl << "{" << endl << " w->deleteLater();" << endl << " const auto callName = d_ptr->m_processingCalls.key(w);" << endl << " Q_ASSERT(!callName.isEmpty());" << endl << " if (callName.isEmpty())" << endl << " return;" << endl << " d_ptr->m_processingCalls.remove(callName);" << endl << " if (!d_ptr->m_waittingCalls.contains(callName))" << endl << " return;" << endl << " const auto args = d_ptr->m_waittingCalls.take(callName);" << endl << " CallQueued(callName, args);" << endl << "}" << endl; // private member hs << "private:" << endl << " " << className << "Private *d_ptr;" << endl; // close the class: hs << "};" << endl << endl; } if (!skipNamespaces) { QStringList last; QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin(); do { QStringList current; QString name; if (it != interfaces.constEnd()) { current = it->constData()->name.split(QLatin1Char('.')); name = current.takeLast(); } int i = 0; while (i < current.count() && i < last.count() && current.at(i) == last.at(i)) ++i; // i parts matched // close last.arguments().count() - i namespaces: for (int j = i; j < last.count(); ++j) hs << QString((last.count() - j - 1 + i) * 2, QLatin1Char(' ')) << "}" << endl; // open current.arguments().count() - i namespaces for (int j = i; j < current.count(); ++j) hs << QString(j * 2, QLatin1Char(' ')) << "namespace " << current.at(j).toLower() << " {" << endl; // add this class: if (!name.isEmpty()) { hs << QString(current.count() * 2, QLatin1Char(' ')) << "typedef ::__" << classNameForInterface(it->constData()->name, Proxy) << " " << name << ";" << endl; } if (it == interfaces.constEnd()) break; ++it; last = current; } while (true); } // close the include guard hs << "#endif" << endl; QString mocName = moc(filename); if (includeMocs && !mocName.isEmpty()) cs << endl << "#include \"" << mocName << "\"" << endl; cs.flush(); hs.flush(); QFile file; const bool headerOpen = openFile(headerName, file); if (headerOpen) file.write(headerData); if (headerName == cppName) { if (headerOpen) file.write(cppData); } else { QFile cppFile; if (openFile(cppName, cppFile)) cppFile.write(cppData); } } static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) { // open the file QString headerName = header(filename); QByteArray headerData; QTextStream hs(&headerData); QString cppName = cpp(filename); QByteArray cppData; QTextStream cs(&cppData); // write the headers writeHeader(hs, false); if (cppName != headerName) writeHeader(cs, true); // include guards: QString includeGuard; if (!headerName.isEmpty() && headerName != QLatin1String("-")) { includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_')); int pos = includeGuard.lastIndexOf(QLatin1Char('/')); if (pos != -1) includeGuard = includeGuard.mid(pos + 1); } else { includeGuard = QLatin1String("QDBUSXML2CPP_ADAPTOR"); } includeGuard = QString(QLatin1String("%1")) .arg(includeGuard); hs << "#ifndef " << includeGuard << endl << "#define " << includeGuard << endl << endl; // include our stuff: hs << "#include " << endl; if (cppName == headerName) hs << "#include " << endl << "#include " << endl; hs << "#include " << endl; foreach (const QString &include, includes) { hs << "#include \"" << include << "\"" << endl; if (headerName.isEmpty()) cs << "#include \"" << include << "\"" << endl; } if (cppName != headerName) { if (!headerName.isEmpty() && headerName != QLatin1String("-")) cs << "#include \"" << headerName << "\"" << endl; cs << "#include " << endl << includeList << endl; hs << forwardDeclarations; } else { hs << includeList; } hs << endl; QString parent = parentClassName; if (parentClassName.isEmpty()) parent = QLatin1String("QObject"); foreach (const QDBusIntrospection::Interface *interface, interfaces) { QString className = classNameForInterface(interface->name, Adaptor); // comment: hs << "/*" << endl << " * Adaptor class for interface " << interface->name << endl << " */" << endl; cs << "/*" << endl << " * Implementation of adaptor class " << className << endl << " */" << endl << endl; // class header: hs << "class " << className << ": public QDBusAbstractAdaptor" << endl << "{" << endl << " Q_OBJECT" << endl << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << endl << " Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << endl << stringify(interface->introspection) << " \"\")" << endl << "public:" << endl << " " << className << "(" << parent << " *parent);" << endl << " virtual ~" << className << "();" << endl << endl; if (!parentClassName.isEmpty()) hs << " inline " << parent << " *parent() const" << endl << " { return static_cast<" << parent << " *>(QObject::parent()); }" << endl << endl; // constructor/destructor cs << className << "::" << className << "(" << parent << " *parent)" << endl << " : QDBusAbstractAdaptor(parent)" << endl << "{" << endl << " // constructor" << endl << " setAutoRelaySignals(true);" << endl << "}" << endl << endl << className << "::~" << className << "()" << endl << "{" << endl << " // destructor" << endl << "}" << endl << endl; hs << "public: // PROPERTIES" << endl; foreach (const QDBusIntrospection::Property &property, interface->properties) { QByteArray type = qtTypeName(property.type, property.annotations); QString constRefType = constRefArg(type); QString getter = propertyGetter(property); QString setter = propertySetter(property); hs << " Q_PROPERTY(" << type << " " << property.name; if (property.access != QDBusIntrospection::Property::Write) hs << " READ " << getter; if (property.access != QDBusIntrospection::Property::Read) hs << " WRITE " << setter; hs << ")" << endl; // getter: if (property.access != QDBusIntrospection::Property::Write) { hs << " " << type << " " << getter << "() const;" << endl; cs << type << " " << className << "::" << getter << "() const" << endl << "{" << endl << " // get the value of property " << property.name << endl << " return qvariant_cast< " << type << " >(parent()->property(\"" << property.name << "\"));" << endl << "}" << endl << endl; } // setter if (property.access != QDBusIntrospection::Property::Read) { hs << " void " << setter << "(" << type << "value);" << endl; cs << "void " << className << "::" << setter << "(" << type << "value)" << endl << "{" << endl << " // set the value of property " << property.name << endl << " parent()->setProperty(\"" << property.name << "\", QVariant::fromValue(value"; if (constRefType.contains(QLatin1String("QDBusVariant"))) cs << ".variant()"; cs << "));" << endl << "}" << endl << endl; } hs << endl; } hs << "public Q_SLOTS: // METHODS" << endl; foreach (const QDBusIntrospection::Method &method, interface->methods) { bool isNoReply = annotationValue(method.annotations, QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"); if (isNoReply && !method.outputArgs.isEmpty()) { fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n", qPrintable(method.name), qPrintable(interface->name)); continue; } hs << " "; if (annotationValue(method.annotations, QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true")) hs << "Q_DECL_DEPRECATED "; QByteArray returnType; if (isNoReply) { hs << "Q_NOREPLY void "; cs << "void "; } else if (method.outputArgs.isEmpty()) { hs << "void "; cs << "void "; } else { returnType = qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out"); hs << returnType << " "; cs << returnType << " "; } QString name = methodName(method); hs << name << "("; cs << className << "::" << name << "("; QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs); hs << ");" << endl; // finished for header cs << ")" << endl << "{" << endl << " // handle method call " << interface->name << "." << methodName(method) << endl; // make the call bool usingInvokeMethod = false; if (parentClassName.isEmpty() && method.inputArgs.count() <= 10 && method.outputArgs.count() <= 1) usingInvokeMethod = true; if (usingInvokeMethod) { // we are using QMetaObject::invokeMethod if (!returnType.isEmpty()) cs << " " << returnType << " " << argNames.at(method.inputArgs.count()) << ";" << endl; static const char invoke[] = " QMetaObject::invokeMethod(parent(), \""; cs << invoke << name << "\""; if (!method.outputArgs.isEmpty()) cs << ", Q_RETURN_ARG(" << qtTypeName(method.outputArgs.at(0).type, method.annotations, 0, "Out") << ", " << argNames.at(method.inputArgs.count()) << ")"; for (int i = 0; i < method.inputArgs.count(); ++i) cs << ", Q_ARG(" << qtTypeName(method.inputArgs.at(i).type, method.annotations, i, "In") << ", " << argNames.at(i) << ")"; cs << ");" << endl; if (!returnType.isEmpty()) cs << " return " << argNames.at(method.inputArgs.count()) << ";" << endl; } else { if (parentClassName.isEmpty()) cs << " //"; else cs << " "; if (!method.outputArgs.isEmpty()) cs << "return "; if (parentClassName.isEmpty()) cs << "static_cast(parent())->"; else cs << "parent()->"; cs << name << "("; int argPos = 0; bool first = true; for (int i = 0; i < method.inputArgs.count(); ++i) { cs << (first ? "" : ", ") << argNames.at(argPos++); first = false; } ++argPos; // skip retval, if any for (int i = 1; i < method.outputArgs.count(); ++i) { cs << (first ? "" : ", ") << argNames.at(argPos++); first = false; } cs << ");" << endl; } cs << "}" << endl << endl; } hs << "Q_SIGNALS: // SIGNALS" << endl; foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { hs << " "; if (annotationValue(signal.annotations, QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true")) hs << "Q_DECL_DEPRECATED "; hs << "void " << signal.name << "("; QStringList argNames = makeArgNames(signal.outputArgs); writeArgList(hs, argNames, signal.annotations, signal.outputArgs); hs << ");" << endl; // finished for header } // close the class: hs << "};" << endl << endl; } // close the include guard hs << "#endif" << endl; QString mocName = moc(filename); if (includeMocs && !mocName.isEmpty()) cs << endl << "#include \"" << mocName << "\"" << endl; cs.flush(); hs.flush(); QFile file; const bool headerOpen = openFile(headerName, file); if (headerOpen) file.write(headerData); if (headerName == cppName) { if (headerOpen) file.write(cppData); } else { QFile cppFile; if (openFile(cppName, cppFile)) cppFile.write(cppData); } } int main(int argc, char **argv) { if (argc < 2) showHelp(); QStringList arguments; arguments.reserve(argc); for (int i = 0; i < argc; ++i) { arguments.append(QString::fromLocal8Bit(argv[i])); } parseCmdLine(arguments); QDBusIntrospection::Interfaces interfaces = readInput(); cleanInterfaces(interfaces); if (!proxyFile.isEmpty() || adaptorFile.isEmpty()) writeProxy(proxyFile, interfaces); if (!adaptorFile.isEmpty()) writeAdaptor(adaptorFile, interfaces); return 0; } dtkcore-5.7.12/tools/settings/000077500000000000000000000000001476226660600162605ustar00rootroot00000000000000dtkcore-5.7.12/tools/settings/CMakeLists.txt000066400000000000000000000017761476226660600210330ustar00rootroot00000000000000set(TARGET_NAME dtk-settings) set(BIN_NAME ${TARGET_NAME}${DTK_VERSION_MAJOR}) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Xml) if(${QT_VERSION_MAJOR} STREQUAL "5") find_package(PkgConfig REQUIRED) pkg_check_modules(QGSettings REQUIRED IMPORTED_TARGET gsettings-qt) endif() add_executable(${BIN_NAME} main.cpp ) target_link_libraries( ${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Xml ${LIB_NAME} ) if(${QT_VERSION_MAJOR} STREQUAL "5") target_link_libraries( ${BIN_NAME} PRIVATE PkgConfig::QGSettings ) endif() target_include_directories( ${BIN_NAME} PUBLIC ../../include/util/ ../../include/dci/ ../../include/log/ ../../include/base/ ../../include/global/ ../../include/DtkCore/ ../../include/settings/ ../../include/filesystem/ ../../include/ ) set_target_properties(${BIN_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME}) install(TARGETS ${BIN_NAME} DESTINATION "${TOOL_INSTALL_DIR}") dtkcore-5.7.12/tools/settings/main.cpp000066400000000000000000000256731476226660600177250ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "settings/dsettings.h" #include "settings/dsettingsgroup.h" #include "settings/dsettingsoption.h" #include #include #include #include #ifndef DTK_SETTINGS_TOOLS_VERSION #define DTK_SETTINGS_TOOLS_VERSION "0.1.2" #endif // DTK_SETTINGS_TOOLS_VERSION static QString CppTemplate = "// This file was generated by dtk-settings-tools version " DTK_SETTINGS_TOOLS_VERSION " \n" "\n" "#include \n" "\n" "void GenerateSettingTranslate()\n" "{\n" "%1" "}\n"; /* * GVariant Type Name/Code C++ Type Name QVariant Type Name * -------------------------------------------------------------------------- * boolean b bool QVariant::Bool * byte y char QVariant::Char * int16 n int QVariant::Int * uint16 q unsigned int QVariant::UInt * int32 i int QVariant::Int * uint32 u unsigned int QVariant::UInt * int64 x long long QVariant::LongLong * uint64 t unsigned long long QVariant::ULongLong * double d double QVariant::Double * string s QString QVariant::String * string array* as QStringList QVariant::StringList * byte array ay QByteArray QVariant::ByteArray * dictionary a{ss} QVariantMap QVariant::Map */ #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QString gsettings_type_from_QVarint(const QMetaType::Type qtype) { switch (qtype) { case QMetaType::Type::Bool: return "b"; case QMetaType::Type::Int: return "i"; case QMetaType::Type::UInt: return "u"; case QMetaType::Type::LongLong: return "x"; case QMetaType::Type::ULongLong: return "t"; case QMetaType::Type::Double: return "d"; case QMetaType::Type::QString: return "s"; case QMetaType::Type::QStringList: return "as"; case QMetaType::Type::QByteArray: return "ay"; case QMetaType::Type::QVariantMap: return "a{ss}"; default: return ""; } } #else QString gsettings_type_from_QVarint(const QVariant::Type qtype) { switch (qtype) { case QVariant::Bool: return "b"; case QVariant::Int: return "i"; case QVariant::UInt: return "u"; case QVariant::LongLong: return "x"; case QVariant::ULongLong: return "t"; case QVariant::Double: return "d"; case QVariant::String: return "s"; case QVariant::StringList: return "as"; case QVariant::ByteArray: return "ay"; case QVariant::Map: return "a{ss}"; default: return ""; } } #endif QString gsettings_value_from_QVarint(const QVariant value) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) switch (value.typeId()) { case QMetaType::Type::Bool: return value.toString(); case QMetaType::Type::Int: return value.toString(); case QMetaType::Type::UInt: return value.toString(); case QMetaType::Type::LongLong: return value.toString(); case QMetaType::Type::ULongLong: return value.toString(); case QMetaType::Type::Double: return value.toString(); case QMetaType::Type::QString: return QString("\"%1\"").arg(value.toString()); case QMetaType::Type::QStringList: return value.toString(); case QMetaType::Type::QByteArray: return value.toString(); case QMetaType::Type::QVariantMap: return value.toString(); default: return ""; } #else switch (value.type()) { case QVariant::Bool: return value.toString(); case QVariant::Int: return value.toString(); case QVariant::UInt: return value.toString(); case QVariant::LongLong: return value.toString(); case QVariant::ULongLong: return value.toString(); case QVariant::Double: return value.toString(); case QVariant::String: return QString("\"%1\"").arg(value.toString()); case QVariant::StringList: return value.toString(); case QVariant::ByteArray: return value.toString(); case QVariant::Map: return value.toString(); default: return ""; } #endif } QJsonObject parseGSettingsMeta(const QString &jsonPath) { QFile jsonFile(jsonPath); jsonFile.open(QIODevice::ReadOnly); auto jsonData = jsonFile.readAll(); jsonFile.close(); QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); return jsonDoc.object().value("gsettings").toObject(); } static bool writeGSettingXML(Dtk::Core::DSettings *settings, QJsonObject gsettingsMeta, const QString &xmlPath) { QDomDocument document; QDomProcessingInstruction header = document.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""); document.appendChild(header); QDomElement schemalist = document.createElement("schemalist"); auto id = gsettingsMeta.value("id").toString(); auto path = gsettingsMeta.value("path").toString(); QDomElement schema = document.createElement("schema"); schema.setAttribute("id", id); schema.setAttribute("path", path); for (QString key : settings->keys()) { auto codeKey = QString(key).replace(".", "-").replace("_", "-"); auto value = settings->option(key)->value(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto gtype = gsettings_type_from_QVarint(static_cast(value.typeId())); #else auto gtype = gsettings_type_from_QVarint(value.type()); #endif if (gtype.isEmpty()) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) qDebug() << "skip unsupported type:" << value.typeId() << key; #else qDebug() << "skip unsupported type:" << value.type() << key; #endif continue; } QDomElement keyXml = document.createElement("key"); keyXml.setAttribute("name", codeKey); keyXml.setAttribute("type", gtype); QString defaultData = gsettings_value_from_QVarint(value); QDomElement defaultEle = document.createElement("default"); QDomCharacterData data = document.createTextNode(defaultData); defaultEle.appendChild(data); keyXml.appendChild(defaultEle); schema.appendChild(keyXml); } schemalist.appendChild(schema); document.appendChild(schemalist); QFile file(xmlPath); if (!file.open(QIODevice::WriteOnly)) { return false; } QTextStream stream(&file); stream << document.toString(); file.close(); return true; } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setOrganizationName("deepin"); app.setApplicationName("dtk-settings-tools"); app.setApplicationVersion(DTK_SETTINGS_TOOLS_VERSION); QCommandLineParser parser; parser.setApplicationDescription("Generate translation of dtksetting."); parser.addHelpOption(); parser.addVersionOption(); QCommandLineOption gsettingsArg(QStringList() << "g" << "gsettings", QCoreApplication::tr("generate gsetting schema"), "xml-file"); QCommandLineOption outputFileArg(QStringList() << "o" << "output", QCoreApplication::tr("Output cpp file"), "cpp-file"); parser.addOption(gsettingsArg); parser.addOption(outputFileArg); parser.addPositionalArgument("json-file", QCoreApplication::tr("Json file description config")); parser.process(app); if (0 == (parser.optionNames().length() + parser.positionalArguments().length())) { parser.showHelp(0); } auto jsonFile = parser.positionalArguments().value(0); auto settings = Dtk::Core::DSettings::fromJsonFile(jsonFile); QMap transtaleMaps; // qDebug() << settings->groupKeys(); for (QString groupKey : settings->groupKeys()) { auto codeKey = QString(groupKey).replace(".", "_"); auto group = settings->group(groupKey); // qDebug() << codeKey << group->name(); // add Name if (!group->name().isEmpty()) { transtaleMaps.insert("group_" + codeKey + "Name", group->name()); } // TODO: only two level for (auto childGroup : group->childGroups()) { auto codeKey = childGroup->key().replace(".", "_"); // qDebug() << codeKey << childGroup->name(); // add Name if (!childGroup->name().isEmpty()) { transtaleMaps.insert("group_" + codeKey + "Name", childGroup->name()); } } } for (QString key : settings->keys()) { auto codeKey = QString(key).replace(".", "_"); auto opt = settings->option(key); QStringList skipI18nKeys = opt->data("i18n_skip_keys").toStringList(); if (skipI18nKeys.contains("all")) { continue; } // add Name if (!opt->name().isEmpty() && !skipI18nKeys.contains("name")) { transtaleMaps.insert(codeKey + "Name", opt->name()); } // add text if (!opt->data("text").toString().isEmpty() && !skipI18nKeys.contains("text")) { transtaleMaps.insert(codeKey + "Text", opt->data("text").toString()); } // add items if (!opt->data("items").toStringList().isEmpty() && !skipI18nKeys.contains("items")) { auto items = opt->data("items").toStringList(); for (int i = 0; i < items.length(); ++i) { transtaleMaps.insert(codeKey + QString("Text%1").arg(i), items.value(i)); } } } QString cppCode; for (auto key : transtaleMaps.keys()) { auto stringCode = QString(" auto %1 = QObject::tr(\"%2\");\n").arg(key).arg(transtaleMaps.value(key)); cppCode.append(stringCode); } if (parser.isSet(outputFileArg)) { QString outputCpp = CppTemplate.arg(cppCode); QFile outputFile(parser.value(outputFileArg)); if (!outputFile.open(QIODevice::WriteOnly)) { qCritical() << "can not open output file!"; exit(1); } outputFile.write(outputCpp.toUtf8()); outputFile.close(); } if (parser.isSet(gsettingsArg)) { QString outputXml = parser.value(gsettingsArg); writeGSettingXML(settings, parseGSettingsMeta(jsonFile), outputXml); } delete settings; return 0; }