[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug report\ndescription: Create a report to help us improve.\nlabels: bug\nbody:\n- type: input\n  id: os\n  attributes:\n    label: OS\n    placeholder: macOS 13.1 (Build 22C65)\n  validations:\n    required: true\n- type: input\n  id: linearmouse\n  attributes:\n    label: LinearMouse\n    placeholder: v0.7.5\n  validations:\n    required: true\n- type: textarea\n  attributes:\n    label: Describe the bug\n    description: A clear and concise description of what the bug is.\n  validations:\n    required: true\n- type: textarea\n  attributes:\n    label: To reproduce\n    description: Steps to reproduce the behavior.\n    placeholder: |\n      1. In this environment...\n      2. With this config...\n      3. Run '...'\n      4. See error...\n  validations:\n    required: false\n- type: textarea\n  attributes:\n    label: Expected behavior\n    description: A clear and concise description of what you expected to happen.\n  validations:\n    required: false\n- type: textarea\n  attributes:\n    label: Anything else?\n    description: |\n      Links? References? Anything that will give us more context about the issue you are encountering!\n\n      Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.\n  validations:\n    required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "contact_links:\n  - name: Discussions\n    url: https://github.com/linearmouse/linearmouse/discussions\n    about: Please ask and answer questions here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature request\ndescription: Suggest an idea for this project.\nlabels: enhancement\nbody:\n- type: input\n  id: os\n  attributes:\n    label: OS\n    placeholder: macOS 13.1 (Build 22C65)\n  validations:\n    required: false\n- type: input\n  id: linearmouse\n  attributes:\n    label: LinearMouse\n    placeholder: v0.7.5\n  validations:\n    required: false\n- type: textarea\n  attributes:\n    label: Is your feature request related to a problem?\n    description: A clear and concise description of what the problem is.\n    placeholder: I'm always frustrated when [...]\n  validations:\n    required: false\n- type: textarea\n  attributes:\n    label: Describe the solution you'd like\n    description: A clear and concise description of what you want to happen.\n    placeholder: I'd like to have per-app settings [...]\n  validations:\n    required: true\n- type: textarea\n  attributes:\n    label: Describe alternatives you've considered\n    description: A clear and concise description of any alternative solutions or features you've considered.\n  validations:\n    required: false\n- type: textarea\n  attributes:\n    label: Additional context\n    description: |\n      Add any other context or screenshots about the feature request here.\n\n      Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.\n  validations:\n    required: false\n"
  },
  {
    "path": ".github/release.yml",
    "content": "changelog:\n  exclude:\n    labels:\n      - ignore for release\n  categories:\n    - title: New features\n      labels:\n        - enhancement\n    - title: Bug fixes\n      labels:\n        - bug\n    - title: Other changes\n      labels:\n        - \"*\"\n"
  },
  {
    "path": ".github/workflows/add-coauthor.yml",
    "content": "name: Add Co-Author to PR\n\non:\n  issue_comment:\n    types: [created]\n\njobs:\n  add-coauthor:\n    runs-on: ubuntu-latest\n    if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/add-author') }}\n\n    permissions:\n      pull-requests: write\n      contents: write\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v3\n        with:\n          fetch-depth: 0\n\n      - name: Add co-author to commit\n        uses: actions/github-script@v6\n        with:\n          script: |\n            try {\n              // Parse the comment to extract the GitHub username\n              const commentBody = context.payload.comment.body;\n              const match = commentBody.match(/\\/add-author\\s+(\\S+)/);\n\n              if (!match || !match[1]) {\n                return;\n              }\n              \n              const username = match[1];\n              \n              // Get user information from GitHub API\n              let userInfo;\n              try {\n                const { data } = await github.rest.users.getByUsername({\n                  username: username\n                });\n                userInfo = data;\n              } catch (error) {\n                await github.rest.issues.createComment({\n                  owner: context.repo.owner,\n                  repo: context.repo.repo,\n                  issue_number: context.payload.issue.number,\n                  body: `Error: Could not find GitHub user \"${username}\"`\n                });\n                return;\n              }\n              \n              // Construct the co-author line\n              // GitHub noreply email format: ID+username@users.noreply.github.com\n              const githubEmail = `${userInfo.id}+${username}@users.noreply.github.com`;\n              const coAuthorLine = `Co-authored-by: ${userInfo.name || username} <${githubEmail}>`;\n              \n              // Get the PR details to find the head branch and latest commit\n              const { data: pullRequest } = await github.rest.pulls.get({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                pull_number: context.payload.issue.number\n              });\n              \n              const headRef = pullRequest.head.ref;\n              const headSha = pullRequest.head.sha;\n              \n              // Get the latest commit message\n              const { data: commit } = await github.rest.git.getCommit({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                commit_sha: headSha\n              });\n              \n              let commitMessage = commit.message;\n              \n              // Check if the co-author is already in the commit message\n              if (commitMessage.includes(coAuthorLine)) {\n                // Add a \"eyes\" reaction to indicate the co-author is already there\n                await github.rest.reactions.createForIssueComment({\n                  owner: context.repo.owner,\n                  repo: context.repo.repo,\n                  comment_id: context.payload.comment.id,\n                  content: 'eyes'\n                });\n                return;\n              }\n              \n              // Add the co-author line to the commit message\n              if (!commitMessage.includes('\\n\\n')) {\n                commitMessage = `${commitMessage}\\n\\n${coAuthorLine}`;\n              } else if (!commitMessage.endsWith('\\n')) {\n                commitMessage = `${commitMessage}\\n${coAuthorLine}`;\n              } else {\n                commitMessage = `${commitMessage}${coAuthorLine}`;\n              }\n              \n              // Create a new commit with the updated message (amend)\n              const { data: latestCommit } = await github.rest.git.getCommit({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                commit_sha: headSha\n              });\n              \n              const { data: tree } = await github.rest.git.getTree({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                tree_sha: latestCommit.tree.sha\n              });\n              \n              const newCommit = await github.rest.git.createCommit({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                message: commitMessage,\n                tree: latestCommit.tree.sha,\n                parents: [headSha]\n              });\n              \n              // Update the reference\n              await github.rest.git.updateRef({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                ref: `heads/${headRef}`,\n                sha: newCommit.data.sha,\n                force: true\n              });\n              \n              // Add a \"rocket\" reaction to indicate success\n              await github.rest.reactions.createForIssueComment({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                comment_id: context.payload.comment.id,\n                content: 'rocket'\n              });\n            } catch (error) {\n              console.error('Error:', error);\n              await github.rest.issues.createComment({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                issue_number: context.payload.issue.number,\n                body: `Error adding co-author: ${error.message}`\n              });\n            }\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non:\n  push:\n    branches:\n      - main\n    tags:\n      - v*\n  pull_request:\n    branches:\n      - main\n\njobs:\n  build:\n    runs-on: macos-26\n    env:\n      APPLE_ID: ${{ secrets.APPLE_ID }}\n      CODE_SIGN_IDENTITY: ${{ secrets.CODE_SIGN_IDENTITY }}\n      DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}\n    steps:\n      - name: Install dependencies\n        run: |\n          brew update\n          brew upgrade swiftformat\n          brew install swiftlint\n      - name: Checkout repository\n        uses: actions/checkout@v4\n      - name: Install the Apple certificate\n        env:\n          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}\n          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}\n          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}\n        if: github.event_name != 'pull_request' && env.BUILD_CERTIFICATE_BASE64 != null\n        run: |\n          # create variables\n          CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12\n          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db\n\n          # import certificate from secrets\n          echo -n \"$BUILD_CERTIFICATE_BASE64\" | base64 --decode --output $CERTIFICATE_PATH\n\n          # create temporary keychain\n          security create-keychain -p \"$KEYCHAIN_PASSWORD\" $KEYCHAIN_PATH\n          security set-keychain-settings -lut 21600 $KEYCHAIN_PATH\n          security unlock-keychain -p \"$KEYCHAIN_PASSWORD\" $KEYCHAIN_PATH\n\n          # import certificate to keychain\n          security import $CERTIFICATE_PATH -P \"$P12_PASSWORD\" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH\n          security list-keychain -d user -s $KEYCHAIN_PATH\n\n          # Configure code signing\n          make configure-release\n      - name: Build pull request\n        if: github.event_name == 'pull_request'\n        run: make configure clean lint test XCODEBUILD_ARGS=\"CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= DEVELOPMENT_TEAM=\"\n      - name: Build\n        if: github.event_name != 'pull_request'\n        run: make\n      - name: Prepublish\n        if: startsWith(github.ref, 'refs/tags/')\n        env:\n          NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }}\n        run: make prepublish\n      - name: Prepare dSYM archive\n        if: startsWith(github.ref, 'refs/tags/')\n        run: cd build/LinearMouse.xcarchive/dSYMs && zip -r \"$GITHUB_WORKSPACE/build/LinearMouse.dSYM.zip\" LinearMouse.app.dSYM\n      - name: Upload dmg\n        if: github.event_name != 'pull_request'\n        uses: actions/upload-artifact@v4\n        with:\n          name: LinearMouse.dmg\n          path: build/LinearMouse.dmg\n          retention-days: 7\n      - name: Release\n        uses: softprops/action-gh-release@v2\n        if: startsWith(github.ref, 'refs/tags/')\n        with:\n          draft: true\n          prerelease: ${{ contains(github.ref, '-') }}\n          files: |\n            build/LinearMouse.dmg\n            build/LinearMouse.dSYM.zip\n          fail_on_unmatched_files: true\n          generate_release_notes: true\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: \"Close stale issues and PRs\"\non:\n  schedule:\n    - cron: \"0 0 * * *\"\n  issue_comment:\n    types: [created]\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v7\n        with:\n          stale-issue-message: \"This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days.\"\n          stale-pr-message: \"This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 10 days.\"\n          close-issue-message: \"This issue was closed because it has been stalled for 5 days with no activity.\"\n          close-pr-message: \"This PR was closed because it has been stalled for 10 days with no activity.\"\n          days-before-issue-stale: 60\n          days-before-pr-stale: 60\n          days-before-issue-close: 5\n          days-before-pr-close: 10\n          stale-issue-label: stale\n          stale-pr-label: stale\n          exempt-issue-labels: help wanted\n          exempt-draft-pr: true\n          exempt-assignees: lujjjh\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## User settings\nxcuserdata/\n\n## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)\n*.xcscmblueprint\n*.xccheckout\n\n## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)\nbuild/\nDerivedData/\n*.moved-aside\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\n\n## Gcc Patch\n/*.gcno\n\n## Configuration\n/Signing.xcconfig\n/Version.xcconfig\n/Release.xcconfig\n\n# macOS\n.DS_Store\n\n# Node.js\nnode_modules\n"
  },
  {
    "path": ".swift-version",
    "content": "5.6\n"
  },
  {
    "path": ".swiftformat",
    "content": "--commas inline\n--disable wrapMultilineStatementBraces\n--enable wrapConditionalBodies\n--enable wrapMultilineFunctionChains\n--header \"MIT License\\nCopyright (c) 2021-{year} LinearMouse\"\n--decimalgrouping 3,5\n--maxwidth 120\n--wraparguments before-first\n--wrapparameters before-first\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "only_rules:\n  - accessibility_trait_for_button\n  - array_init\n  - blanket_disable_command\n  - block_based_kvo\n  - class_delegate_protocol\n  - closing_brace\n  - closure_end_indentation\n  - closure_parameter_position\n  - closure_spacing\n  - collection_alignment\n  - colon\n  - comma\n  - comma_inheritance\n  - compiler_protocol_init\n  - computed_accessors_order\n  - conditional_returns_on_newline\n  - contains_over_filter_count\n  - contains_over_filter_is_empty\n  - contains_over_first_not_nil\n  - contains_over_range_nil_comparison\n  - control_statement\n  - custom_rules\n  - deployment_target\n  - direct_return\n  - discarded_notification_center_observer\n  - discouraged_assert\n  - discouraged_direct_init\n  - discouraged_none_name\n  - discouraged_object_literal\n  - discouraged_optional_collection\n  - duplicate_conditions\n  - duplicate_enum_cases\n  - duplicate_imports\n  - duplicated_key_in_dictionary_literal\n  - dynamic_inline\n  - empty_collection_literal\n  - empty_count\n  - empty_enum_arguments\n  - empty_parameters\n  - empty_parentheses_with_trailing_closure\n  - empty_string\n  - empty_xctest_method\n  - enum_case_associated_values_count\n  - explicit_init\n  - fallthrough\n  - fatal_error_message\n  - final_test_case\n  - first_where\n  - flatmap_over_map_reduce\n  - for_where\n  - generic_type_name\n  - ibinspectable_in_extension\n  - identical_operands\n  - implicit_getter\n  - implicit_return\n  - inclusive_language\n  - invalid_swiftlint_command\n  - is_disjoint\n  - joined_default_parameter\n  - last_where\n  - leading_whitespace\n  - legacy_cggeometry_functions\n  - legacy_constant\n  - legacy_constructor\n  - legacy_hashing\n  - legacy_multiple\n  - legacy_nsgeometry_functions\n  - legacy_random\n  - literal_expression_end_indentation\n  - lower_acl_than_parent\n  - mark\n  - modifier_order\n  - multiline_arguments\n  - multiline_arguments_brackets\n  - multiline_function_chains\n  - multiline_literal_brackets\n  - multiline_parameters\n  - multiline_parameters_brackets\n  - nimble_operator\n  - number_separator\n  - no_fallthrough_only\n  - no_space_in_method_call\n  - non_optional_string_data_conversion\n  - non_overridable_class_declaration\n  - notification_center_detachment\n  - ns_number_init_as_function_reference\n  - nsobject_prefer_isequal\n  - operator_usage_whitespace\n  - operator_whitespace\n  - optional_data_string_conversion\n  - overridden_super_call\n  - prefer_key_path\n  - prefer_self_in_static_references\n  - prefer_self_type_over_type_of_self\n  - prefer_zero_over_explicit_init\n  - private_action\n  - private_outlet\n  - private_subject\n  - private_swiftui_state\n  - private_unit_test\n  - prohibited_super_call\n  - protocol_property_accessors_order\n  - reduce_boolean\n  - reduce_into\n  - redundant_discardable_let\n  - redundant_nil_coalescing\n  - redundant_objc_attribute\n  - redundant_optional_initialization\n  - redundant_sendable\n  - redundant_set_access_control\n  - redundant_string_enum_value\n  - redundant_type_annotation\n  - redundant_void_return\n  - required_enum_case\n  - return_arrow_whitespace\n  - return_value_from_void_function\n  - self_binding\n  - self_in_property_initialization\n  - shorthand_operator\n  - shorthand_optional_binding\n  - sorted_first_last\n  - statement_position\n  - static_operator\n  - static_over_final_class\n  - strong_iboutlet\n  - superfluous_disable_command\n  - superfluous_else\n  - switch_case_alignment\n  - switch_case_on_newline\n  - syntactic_sugar\n  - test_case_accessibility\n  - toggle_bool\n  - trailing_closure\n  - trailing_comma\n  - trailing_newline\n  - trailing_semicolon\n  - trailing_whitespace\n  - unavailable_condition\n  - unavailable_function\n  - unneeded_break_in_switch\n  - unneeded_override\n  - unneeded_parentheses_in_closure_argument\n  - unowned_variable_capture\n  - untyped_error_in_catch\n  - unused_closure_parameter\n  - unused_control_flow_label\n  - unused_enumerated\n  - unused_optional_binding\n  - unused_setter_value\n  - valid_ibinspectable\n  - vertical_parameter_alignment\n  - vertical_parameter_alignment_on_call\n  - vertical_whitespace_closing_braces\n  - vertical_whitespace_opening_braces\n  - void_function_in_ternary\n  - void_return\n  - xct_specific_matcher\n  - xctfail_message\n  - yoda_condition\nanalyzer_rules:\n  - capture_variable\n  - typesafe_array_init\n  - unneeded_synthesized_initializer\n  - unused_declaration\n  - unused_import\nredundant_discardable_let:\n  ignore_swiftui_view_bodies: true\nfor_where:\n  allow_for_as_filter: true\nnumber_separator:\n  minimum_length: 5\nredundant_type_annotation:\n  consider_default_literal_types_redundant: true\nunneeded_override:\n  affect_initializers: true\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.formatOnSave\": true\n}\n"
  },
  {
    "path": "ACCESSIBILITY.md",
    "content": "# Accessibility permission\n\nLinearMouse requires accessibility features to work properly.\nYou need to grant Accessibility permission at first launch.\n\n## Grant Accessibility permission\n\n1. Click “Open Accessibility”.\n2. Click the lock to make changes.\n3. Toggle “LinearMouse” on.\n\nhttps://user-images.githubusercontent.com/3000535/173173454-b4b8e7ae-5184-4b7a-ba72-f6ce8041f721.mp4\n\n## Not working?\n\nIf LinearMouse continues to display accessibility permission request window even after it has been\ngranted, it's likely due to a common macOS bug.\n\nTo resolve this issue, you can try the following steps:\n\n1. Remove LinearMouse from accessibility permissions using the \"-\" button.\n2. Re-add it.\n\nIf the previous steps did not resolve the issue, you can try the following:\n\n1. Quit LinearMouse.\n2. Open Terminal.app.\n3. <p>Copy and paste the following command:</p>\n   <pre><code>tccutil reset Accessibility com.lujjjh.LinearMouse</code></pre>\n   Then press the return key.\n4. Launch LinearMouse and try again.\n"
  },
  {
    "path": "CLAUDE.md",
    "content": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nLinearMouse is a macOS utility app that enhances mouse and trackpad functionality. It's built with Swift and uses SwiftUI for the user interface. The app provides customizable mouse button mappings, scrolling behavior, and pointer settings that can be configured per-device, per-application, or per-display.\n\n## Development Commands\n\n### Build and Test\n```bash\n# Build the project\nxcodebuild -project LinearMouse.xcodeproj -scheme LinearMouse\n\n# Run tests\nmake test\n# or\nxcodebuild test -project LinearMouse.xcodeproj -scheme LinearMouse\n\n# Full build pipeline (configure, clean, lint, test, package)\nmake all\n```\n\n### Code Quality\n```bash\n# Lint the codebase\nmake lint\n# or run individually:\nswiftformat --lint .\nswiftlint .\n\n# Clean build artifacts\nmake clean\n```\n\n### Packaging\n```bash\n# Create DMG package\nmake package\n\n# For release (requires signing certificates)\nmake configure-release\nmake prepublish\n```\n\n### Configuration Schema Generation\n```bash\n# Generate JSON schema from TypeScript definitions\nnpm run generate:json-schema\n```\n\n## Architecture Overview\n\n### Core Components\n\n1. **EventTransformer System** (`LinearMouse/EventTransformer/`):\n   - `EventTransformerManager`: Central coordinator that manages event processing\n   - Individual transformers handle specific functionality (scrolling, button mapping, etc.)\n   - Uses LRU cache for performance optimization\n\n2. **Configuration System** (`LinearMouse/Model/Configuration/`):\n   - `Configuration.swift`: Main configuration model with JSON schema validation\n   - `Scheme.swift`: Defines device-specific settings\n   - `DeviceMatcher.swift`: Logic for matching devices to configurations\n\n3. **Device Management** (`LinearMouse/Device/`):\n   - `DeviceManager.swift`: Manages connected input devices\n   - `Device.swift`: Represents individual input devices\n\n4. **Event Processing** (`LinearMouse/EventTap/`):\n   - `GlobalEventTap.swift`: Captures system-wide input events\n   - `EventTap.swift`: Base event handling functionality\n\n5. **User Interface** (`LinearMouse/UI/`):\n   - SwiftUI-based settings interface\n   - Modular components for different settings categories\n   - State management using `@Published` properties\n\n### Custom Modules\n\nThe project includes several custom Swift packages in the `Modules/` directory:\n\n- **KeyKit**: Keyboard input handling and simulation\n- **PointerKit**: Mouse/trackpad device interaction\n- **GestureKit**: Gesture recognition (zoom, navigation swipes)\n- **DockKit**: Dock integration utilities\n- **ObservationToken**: Observation pattern utilities\n\n### Key Patterns\n\n1. **Event Transformation Pipeline**: Events flow through multiple transformers in sequence\n2. **Configuration-Driven Behavior**: All functionality is controlled by JSON configuration\n3. **Device Matching**: Settings are applied based on device type, application, or display\n4. **State Management**: Uses Combine framework for reactive state updates\n\n## Important Development Notes\n\n- The app requires accessibility permissions to function\n- Event processing happens at the system level using CGEvent\n- Configuration is stored as JSON and validated against a schema\n- The project uses Swift Package Manager for dependencies\n- Localization is handled through Crowdin integration\n- Code signing is required for distribution (see `Scripts/` directory)\n\n## Testing\n\n- Unit tests are in `LinearMouseUnitTests/`\n- Focus on testing event transformers and configuration parsing\n- Run tests before submitting changes: `make test`\n\n## Configuration Structure\n\nThe app uses a JSON configuration format with:\n- `schemes`: Array of device-specific configurations\n- Each scheme can target specific devices, applications, or displays\n- Settings include button mappings, scrolling behavior, and pointer adjustments\n- Configuration schema is defined in `Documentation/Configuration.d.ts`"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nfeedback@linearmouse.org.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING-cn.md",
    "content": "# 贡献指南\n\n感谢你投入时间为 LinearMouse 做出贡献。\n\n阅读我们的[行为准则](CODE_OF_CONDUCT.md)，以保持我们的社区平易近人，受到尊重。\n\n## 构建指南\n\n在 macOS 上构建 LinearMouse 的指南。\n\n### 设置仓库\n\n```sh\n$ git clone https://github.com/linearmouse/linearmouse.git\n$ cd linearmouse\n```\n\n### 配置代码签名\n\nApple 要求代码签名。你可以运行以下命令来生成代码签名配置。\n\n```\n$ make configure\n```\n\n> 注：如果你希望为 LinearMouse 贡献代码，请不要在 Xcode 中直接修改“Signing & Capabilities”。使用 `make configure` 或者修改 `Signing.xcconfig`。\n\n如果在你的钥匙串中没有代码签名证书，会生成一份使用 ad-hoc 证书签名应用的配置。\n\n使用 ad-hoc 证书，你需要为每次构建[授予辅助功能权限](https://github.com/linearmouse/linearmouse#accessibility-permission)。因此，推荐使用 Apple Development 证书。你可以[在 Xcode 中](https://help.apple.com/xcode/mac/current/#/dev154b28f09) 创建 Apple Development 证书，这是完全免费的。\n\n### 构建\n\n现在，你可以运行以下命令来构建和打包 LinearMouse 了。\n\n```sh\n$ make\n```\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing guide\n\nThank you for investing your time in contributing to LinearMouse!\n\nRead our [Code of Conduct](CODE_OF_CONDUCT.md) to keep our community approachable and respectable.\n\n## Build instructions\n\nInstructions for building LinearMouse on macOS.\n\n### Dependencies\n\n- [Xcode](https://apps.apple.com/app/xcode/id497799835), obviously\n- [SwiftLint](https://github.com/realm/SwiftLint), used to lint Swift files\n- [SwiftFormat](https://github.com/nicklockwood/SwiftFormat), used to format Swift files\n- `npm` & [ts-json-schema-generator](https://www.npmjs.com/package/ts-json-schema-generator), used to generate and document the custom configuration JSON scheme\n\nInstall tools using brew:\n\n```bash\n$ brew install npm swiftlint swiftformat\n```\n\nInstall npm dependencies from the [package.json](./package.json)\n\n```bash\n$ npm install\n```\n\n### Setup the repository\n\n```sh\n$ git clone https://github.com/linearmouse/linearmouse.git\n$ cd linearmouse\n```\n\n### Configure code signing\n\nCode signing is required by Apple. You can generate a code signing configuration by running\n\n```\n$ make configure\n```\n\n> Note: If you want to contribute to LinearMouse, please don't modify the ‘Signing & Capabilities’ configurations directly in Xcode. Instead, use `make configure` or modify the `Signing.xcconfig`.\n\nIf there are no available code signing certificates in your Keychain, it will generate a configuration that uses ad-hoc certificates to sign the app.\n\nBy using ad-hoc certificates, you'll have to [grant accessibility permissions](https://github.com/linearmouse/linearmouse#accessibility-permission) for each builds.\nIn that case, using Apple Development certificates is recommended.\nYou can create an Apple Development certificate [in Xcode](https://help.apple.com/xcode/mac/current/#/dev154b28f09), which is totally free.\n\n### Build\n\nNow, you can build and package LinearMouse by running\n\n```sh\n$ make\n```\n"
  },
  {
    "path": "Config.xcconfig",
    "content": "CURRENT_PROJECT_VERSION = dev\nMARKETING_VERSION = $(CURRENT_PROJECT_VERSION)\n\nPRODUCT_BUNDLE_IDENTIFIER = com.lujjjh.dev.LinearMouse\nASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev\n\n#include? \"Signing.xcconfig\"\n#include? \"Version.xcconfig\"\n#include? \"Release.xcconfig\"\n"
  },
  {
    "path": "Documentation/Configuration.d.ts",
    "content": "type SingleValueOrArray<T> = T | T[];\n\n/** @asType number */\ntype Int = number;\n\n/** @pattern ^\\d+$ */\ntype IntString = string;\n\n/** @pattern ^0x[0-9a-fA-F]+$ */\ntype HexString = string;\n\ntype PhysicalButton = Primary | Secondary | Auxiliary | Back | Forward | number;\n\n/**\n * @title Unset\n * @description A special value that explicitly restores a setting to the system or device default. Currently supported in pointer settings; may be supported more broadly in the future.\n */\nexport type Unset = \"unset\";\n\n/**\n * @description Primary button, usually the left button.\n */\ntype Primary = 0;\n\n/**\n * @description Secondary button, usually the right button.\n */\ntype Secondary = 1;\n\n/**\n * @description Auxiliary button, usually the wheel button or the middle button.\n */\ntype Auxiliary = 2;\n\n/**\n * @description Forth button, typically the back button.\n */\ntype Back = 3;\n\n/**\n * @description Fifth button, typically the forward button.\n */\ntype Forward = 4;\n\nexport type Configuration = {\n  $schema?: string;\n\n  /**\n   * @title Schemes\n   * @description A scheme is a collection of settings that are activated in specified circumstances.\n   * @examples [{\"if\":{\"device\":{\"category\":\"mouse\"}},\"scrolling\":{\"reverse\":\"vertical\"}}]\n   */\n  schemes?: Scheme[];\n};\n\ntype Scheme = {\n  /**\n   * @title Scheme activation conditions\n   * @description This value can be a single condition or an array. A scheme is activated if at least one of the conditions is met.\n   */\n  if?: SingleValueOrArray<Scheme.If>;\n\n  /**\n   * @title Scrolling settings\n   * @description Customize the scrolling behavior.\n   */\n  scrolling?: Scheme.Scrolling;\n\n  /**\n   * @title Pointer settings\n   * @description Customize the pointer acceleration and speed.\n   */\n  pointer?: Scheme.Pointer;\n\n  /**\n   * @title Buttons settings\n   * @description Customize the buttons behavior.\n   */\n  buttons?: Scheme.Buttons;\n};\n\ndeclare namespace Scheme {\n  type If = {\n    /**\n     * @title Device\n     * @description Match one or more devices. If not provided, the scheme is activated on all devices.\n     */\n    device?: If.Device;\n\n    /**\n     * @title App\n     * @description Match apps by providing the bundle ID. For example, `com.apple.Safari`.\n     */\n    app?: string;\n\n    /**\n     * @title Parent app\n     * @description Match apps by providing the bundle ID of the parent process. For example, `org.polymc.PolyMC`.\n     */\n    parentApp?: string;\n\n    /**\n     * @title Group app\n     * @description Match apps by providing the bundle ID of the process group. For example, `org.polymc.PolyMC`.\n     */\n    groupApp?: string;\n\n    /**\n     * @title Process name\n     * @description Match by the executable file name of the frontmost process (from NSRunningApplication.executableURL.lastPathComponent). Case-sensitive.\n     */\n    processName?: string;\n\n    /**\n     * @title Process path\n     * @description Match by the absolute executable path of the frontmost process (from NSRunningApplication.executableURL.path). Case-sensitive.\n     */\n    processPath?: string;\n\n    /**\n     * @title Display name\n     * @description Match displays by providing the display name. For example, `DELL P2415Q`.\n     */\n    display?: string;\n  };\n\n  namespace If {\n    type Device = {\n      /**\n       * @title Vendor ID\n       * @description The vendor ID of the devices.\n       * @examples [\"0xA123\"]\n       */\n      vendorID?: HexString | Int;\n\n      /**\n       * @title Product ID\n       * @description The product ID of the devices.\n       * @examples [\"0xA123\"]\n       */\n      productID?: HexString | Int;\n\n      /**\n       * @title Product name\n       * @description The product name of the devices.\n       */\n      productName?: string;\n\n      /**\n       * @title Serial number\n       * @description The serial number of the devices.\n       */\n      serialNumber?: string;\n\n      /**\n       * @title Category\n       * @description The category of the devices.\n       */\n      category?: SingleValueOrArray<Category>;\n    };\n\n    /**\n     * @title Mouse\n     * @description Match mouse devices.\n     */\n    type Mouse = \"mouse\";\n\n    /**\n     * @title Trackpad\n     * @description Match trackpad devices.\n     */\n    type Trackpad = \"trackpad\";\n\n    type Category = Mouse | Trackpad;\n  }\n\n  type Scrolling = {\n    /**\n     * @title Reverse scrolling\n     */\n    reverse?: Scrolling.Bidirectional<boolean>;\n\n    /**\n     * @title Scroll distance\n     * @description The distance after rolling the wheel.\n     */\n    distance?: Scrolling.Bidirectional<Scrolling.Distance>;\n\n    /**\n     * @description The scrolling acceleration.\n     * @default 1\n     */\n    acceleration?: Scrolling.Bidirectional<number>;\n\n    /**\n     * @description The scrolling speed.\n     * @default 0\n     */\n    speed?: Scrolling.Bidirectional<number>;\n\n    /**\n     * @title Smoothed scrolling\n     * @description Use a preset curve or fine-tune response, speed, acceleration, and inertia.\n     */\n    smoothed?: Scrolling.Bidirectional<Scrolling.Smoothed>;\n\n    /**\n     * @title Modifier keys settings\n     */\n    modifiers?: Scrolling.Bidirectional<Scrolling.Modifiers>;\n  };\n\n  namespace Scrolling {\n    type Bidirectional<T> =\n      | T\n      | undefined\n      | {\n          vertical?: T;\n          horizontal?: T;\n        };\n\n    /**\n     * @description The scrolling distance will not be modified.\n     */\n    type Auto = \"auto\";\n\n    type Distance = Auto | Distance.Line | Distance.Pixel;\n\n    namespace Distance {\n      /**\n       * @description The scrolling distance in lines.\n       */\n      type Line = Int | IntString;\n\n      /**\n       * @description The scrolling distance in pixels.\n       * @pattern ^\\d[1-9]*(\\.\\d+)?px\n       */\n      type Pixel = string;\n    }\n\n    type Smoothed = {\n      /**\n       * @description Set to `false` to explicitly disable inherited smoothed scrolling for this direction.\n       * @default true\n       */\n      enabled?: boolean;\n\n      /**\n       * @description The preset curve to use.\n       * @default \"natural\"\n       */\n      preset?: Smoothed.Preset;\n\n      /**\n       * @description How quickly the scrolling responds to input.\n       */\n      response?: number;\n\n      /**\n       * @description The scrolling speed.\n       */\n      speed?: number;\n\n      /**\n       * @description The scrolling acceleration.\n       */\n      acceleration?: number;\n\n      /**\n       * @description The scrolling inertia.\n       */\n      inertia?: number;\n    };\n\n    namespace Smoothed {\n      type Preset =\n        | \"custom\"\n        | \"linear\"\n        | \"easeIn\"\n        | \"easeOut\"\n        | \"easeInOut\"\n        | \"easeOutIn\"\n        | \"quadratic\"\n        | \"cubic\"\n        | \"quartic\"\n        | \"easeOutCubic\"\n        | \"easeInOutCubic\"\n        | \"easeOutQuartic\"\n        | \"easeInOutQuartic\"\n        | \"quintic\"\n        | \"sine\"\n        | \"exponential\"\n        | \"circular\"\n        | \"back\"\n        | \"bounce\"\n        | \"elastic\"\n        | \"spring\"\n        | \"natural\"\n        | \"smooth\"\n        | \"snappy\"\n        | \"gentle\";\n    }\n\n    type Modifiers = {\n      /**\n       * @description The action when command key is pressed.\n       */\n      command?: Modifiers.Action;\n\n      /**\n       * @description The action when shift key is pressed.\n       */\n      shift?: Modifiers.Action;\n\n      /**\n       * @description The action when option key is pressed.\n       */\n      option?: Modifiers.Action;\n\n      /**\n       * @description The action when control key is pressed.\n       */\n      control?: Modifiers.Action;\n    };\n\n    namespace Modifiers {\n      /**\n       * @deprecated\n       * @description Default action.\n       */\n      type None = { type: \"none\" };\n\n      /**\n       * @description Default action.\n       */\n      type Auto = { type: \"auto\" };\n\n      /**\n       * @description Ignore modifier.\n       */\n      type Ignore = { type: \"ignore\" };\n\n      /**\n       * @description No action.\n       */\n      type PreventDefault = { type: \"preventDefault\" };\n\n      /**\n       * @description Alter the scrolling orientation from vertical to horizontal or vice versa.\n       */\n      type AlterOrientation = {\n        type: \"alterOrientation\";\n      };\n\n      /**\n       * @description Scale the scrolling speed.\n       */\n      type ChangeSpeed = {\n        type: \"changeSpeed\";\n\n        /**\n         * @description The factor to scale the scrolling speed.\n         */\n        scale: number;\n      };\n\n      /**\n       * @description Zoom in and out using ⌘+ and ⌘-.\n       */\n      type Zoom = {\n        type: \"zoom\";\n      };\n\n      /**\n       * @description Zoom in and out using pinch gestures.\n       */\n      type PinchZoom = {\n        type: \"pinchZoom\";\n      };\n\n      type Action =\n        | None\n        | Auto\n        | Ignore\n        | PreventDefault\n        | AlterOrientation\n        | ChangeSpeed\n        | Zoom\n        | PinchZoom;\n    }\n  }\n\n  type Pointer = {\n    /**\n     * @title Pointer acceleration\n     * @description A number to set acceleration, or \"unset\" to restore system default. If omitted, the previous/merged value applies.\n     * @minimum 0\n     * @maximum 20\n     */\n    acceleration?: number | Unset;\n\n    /**\n     * @title Pointer speed\n     * @description A number to set speed, or \"unset\" to restore device default. If omitted, the previous/merged value applies.\n     * @minimal 0\n     * @maximum 1\n     */\n    speed?: number | Unset;\n\n    /**\n     * @title Disable pointer acceleration\n     * @description If the value is true, the pointer acceleration will be disabled and acceleration and speed will not take effect.\n     * @default false\n     */\n    disableAcceleration?: boolean;\n\n    /**\n     * @title Redirects to scroll\n     * @description If the value is true, pointer movements will be redirected to scroll events.\n     * @default false\n     */\n    redirectsToScroll?: boolean;\n  };\n\n  type Buttons = {\n    /**\n     * @title Button mappings\n     * @description Assign actions to buttons.\n     */\n    mappings?: Buttons.Mapping[];\n\n    /**\n     * @title Universal back and forward\n     * @description If the value is true, the back and forward side buttons will be enabled in Safari and some other apps that do not handle these side buttons correctly. If the value is \"backOnly\" or \"forwardOnly\", only universal back or universal forward will be enabled.\n     * @default false\n     */\n    universalBackForward?: Buttons.UniversalBackForward;\n\n    /**\n     * @title Switch primary and secondary buttons\n     * @description If the value is true, the primary button will be the right button and the secondary button will be the left button.\n     * @default false\n     */\n    switchPrimaryButtonAndSecondaryButtons?: boolean;\n\n    /**\n     * @title Debounce button clicks\n     * @description Ignore rapid clicks with a certain time period.\n     */\n    clickDebouncing?: Buttons.ClickDebouncing;\n\n    /**\n     * @title Gesture button\n     * @description Press and hold a button while dragging to trigger gestures like switching desktop spaces or opening Mission Control.\n     */\n    gesture?: Buttons.Gesture;\n\n    /**\n     * @title Auto scroll\n     * @description Click or hold a mouse button, then move the pointer to continuously scroll like the Windows middle-button autoscroll behavior.\n     */\n    autoScroll?: Buttons.AutoScroll;\n  };\n\n  namespace Buttons {\n    type AutoScroll = {\n      /**\n       * @description Indicates if auto scroll is enabled.\n       * @default false\n       */\n      enabled?: boolean;\n\n      /**\n       * @title Activation mode\n       * @description Use \\\"toggle\\\" to click once and move until clicking again, \\\"hold\\\" to scroll only while the trigger stays pressed, or provide both to support both behaviors.\n       */\n      mode?: SingleValueOrArray<AutoScroll.Mode>;\n\n      /**\n       * @description Adjust the auto scroll speed multiplier.\n       * @default 1\n       */\n      speed?: number;\n\n      /**\n       * @description If true, a plain middle click on a pressable element such as a link will keep its native behavior when possible.\n       * @default false\n       */\n      preserveNativeMiddleClick?: boolean;\n\n      /**\n       * @title Trigger\n       * @description Choose the mouse button and modifier keys used to activate auto scroll.\n       */\n      trigger?: AutoScroll.Trigger;\n    };\n\n    namespace AutoScroll {\n      /**\n       * @description Click once to enter auto scroll and click again to exit.\n       */\n      type Toggle = \"toggle\";\n\n      /**\n       * @description Auto scroll is active only while the trigger button remains pressed.\n       */\n      type Hold = \"hold\";\n\n      type Mode = Toggle | Hold;\n\n      type Trigger = {\n        /**\n         * @title Button number\n         * @description The button number. See https://developer.apple.com/documentation/coregraphics/cgmousebutton\n         */\n        button: Mapping.Button;\n\n        /**\n         * @description Indicates if the command modifier key should be pressed.\n         */\n        command?: boolean;\n\n        /**\n         * @description Indicates if the shift modifier key should be pressed.\n         */\n        shift?: boolean;\n\n        /**\n         * @description Indicates if the option modifier key should be pressed.\n         */\n        option?: boolean;\n\n        /**\n         * @description Indicates if the control modifier key should be pressed.\n         */\n        control?: boolean;\n      };\n    }\n\n    type Mapping = (\n      | {\n          /**\n           * @title Button number\n           * @description The button number. See https://developer.apple.com/documentation/coregraphics/cgmousebutton\n           */\n          button: Mapping.Button;\n\n          /**\n           * @description Indicates if key repeat is enabled. If the value is true, the action will be repeatedly executed when the button is hold according to the key repeat settings in System Settings.\n           */\n          repeat?: boolean;\n\n          /**\n           * @description Indicates if keyboard shortcut actions should stay pressed while the button is held. When enabled, LinearMouse sends key down on button press and key up on button release instead of repeating the shortcut.\n           */\n          hold?: boolean;\n        }\n      | {\n          /**\n           * @title Scroll direction\n           * @description Map scroll events to specific actions.\n           */\n          scroll: Mapping.ScrollDirection;\n        }\n    ) & {\n      /**\n       * @description Indicates if the command modifier key should be pressed.\n       */\n      command?: boolean;\n\n      /**\n       * @description Indicates if the shift modifier key should be pressed.\n       */\n      shift?: boolean;\n\n      /**\n       * @description Indicates if the option modifier key should be pressed.\n       */\n      option?: boolean;\n\n      /**\n       * @description Indicates if the control modifier key should be pressed.\n       */\n      control?: boolean;\n\n      /**\n       * @title Action\n       */\n      action?: Mapping.Action;\n    };\n\n    namespace Mapping {\n      type Button = PhysicalButton | LogitechControlButton;\n\n      type LogitechControlButton = {\n        /**\n         * @description Logitech control button identifier.\n         */\n        kind: \"logitechControl\";\n\n        /**\n         * @description Logitech control ID (CID).\n         */\n        controlID: Int;\n\n        /**\n         * @description Match a specific Logitech device product ID when needed.\n         */\n        productID?: HexString | Int;\n\n        /**\n         * @description Match a specific Logitech device serial number when needed.\n         */\n        serialNumber?: string;\n      };\n\n      type Action =\n        | SimpleAction\n        | Run\n        | MouseWheelScrollUpWithDistance\n        | MouseWheelScrollDownWithDistance\n        | MouseWheelScrollLeftWithDistance\n        | MouseWheelScrollRightWithDistance\n        | KeyPress;\n\n      type SimpleAction =\n        | Auto\n        | None\n        | MissionControlSpaceLeft\n        | MissionControlSpaceRight\n        | MissionControl\n        | AppExpose\n        | Launchpad\n        | ShowDesktop\n        | LookUpAndDataDetectors\n        | SmartZoom\n        | DisplayBrightnessUp\n        | DisplayBrightnessDown\n        | MediaVolumeUp\n        | MediaVolumeDown\n        | MediaMute\n        | MediaPlayPause\n        | MediaNext\n        | MediaPrevious\n        | MediaFastForward\n        | MediaRewind\n        | KeyboardBrightnessUp\n        | KeyboardBrightnessDown\n        | MouseWheelScrollUp\n        | MouseWheelScrollDown\n        | MouseWheelScrollLeft\n        | MouseWheelScrollRight\n        | MouseButtonLeft\n        | MouseButtonMiddle\n        | MouseButtonRight\n        | MouseButtonBack\n        | MouseButtonForward;\n\n      /**\n       * @description Do not modify the button behavior.\n       */\n      type Auto = \"auto\";\n\n      /**\n       * @description Prevent the button events.\n       */\n      type None = \"none\";\n\n      /**\n       * @description Mission Control.\n       */\n      type MissionControl = \"missionControl\";\n\n      /**\n       * @description Mission Control: Move left a space.\n       */\n      type MissionControlSpaceLeft = \"missionControl.spaceLeft\";\n\n      /**\n       * @description Mission Control: Move right a space.\n       */\n      type MissionControlSpaceRight = \"missionControl.spaceRight\";\n\n      /**\n       * @description Application windows.\n       */\n      type AppExpose = \"appExpose\";\n\n      /**\n       * @description Launchpad.\n       */\n      type Launchpad = \"launchpad\";\n\n      /**\n       * @description Show desktop.\n       */\n      type ShowDesktop = \"showDesktop\";\n\n      /**\n       * @description Look up & data detectors.\n       */\n      type LookUpAndDataDetectors = \"lookUpAndDataDetectors\";\n\n      /**\n       * @description Smart zoom.\n       */\n      type SmartZoom = \"smartZoom\";\n\n      /**\n       * @description Display: Brightness up.\n       */\n      type DisplayBrightnessUp = \"display.brightnessUp\";\n\n      /**\n       * @description Display: Brightness down.\n       */\n      type DisplayBrightnessDown = \"display.brightnessDown\";\n\n      /**\n       * @description Media: Volume up.\n       */\n      type MediaVolumeUp = \"media.volumeUp\";\n\n      /**\n       * @description Media: Volume down.\n       */\n      type MediaVolumeDown = \"media.volumeDown\";\n\n      /**\n       * @description Media: Toggle mute.\n       */\n      type MediaMute = \"media.mute\";\n\n      /**\n       * @description Media: Play / pause.\n       */\n      type MediaPlayPause = \"media.playPause\";\n\n      /**\n       * @description Media: Next.\n       */\n      type MediaNext = \"media.next\";\n\n      /**\n       * @description Media: Previous.\n       */\n      type MediaPrevious = \"media.previous\";\n\n      /**\n       * @description Media: Fast forward.\n       */\n      type MediaFastForward = \"media.fastForward\";\n\n      /**\n       * @description Media: Rewind.\n       */\n      type MediaRewind = \"media.rewind\";\n\n      /**\n       * @description Keyboard: Brightness up.\n       */\n      type KeyboardBrightnessUp = \"keyboard.brightnessUp\";\n\n      /**\n       * @description Keyboard: Brightness down.\n       */\n      type KeyboardBrightnessDown = \"keyboard.brightnessDown\";\n\n      /**\n       * @description Mouse: Wheel: Scroll up.\n       */\n      type MouseWheelScrollUp = \"mouse.wheel.scrollUp\";\n\n      /**\n       * @description Mouse: Wheel: Scroll down.\n       */\n      type MouseWheelScrollDown = \"mouse.wheel.scrollDown\";\n\n      /**\n       * @description Mouse: Wheel: Scroll left.\n       */\n      type MouseWheelScrollLeft = \"mouse.wheel.scrollLeft\";\n\n      /**\n       * @description Mouse: Wheel: Scroll right.\n       */\n      type MouseWheelScrollRight = \"mouse.wheel.scrollRight\";\n\n      /**\n       * @description Mouse: Button: Act as left button.\n       */\n      type MouseButtonLeft = \"mouse.button.left\";\n\n      /**\n       * @description Mouse: Button: Act as middle button.\n       */\n      type MouseButtonMiddle = \"mouse.button.middle\";\n\n      /**\n       * @description Mouse: Button: Act as right button.\n       */\n      type MouseButtonRight = \"mouse.button.right\";\n\n      /**\n       * @description Mouse: Button: Act as back button.\n       */\n      type MouseButtonBack = \"mouse.button.back\";\n\n      /**\n       * @description Mouse: Button: Act as forward button.\n       */\n      type MouseButtonForward = \"mouse.button.forward\";\n\n      type Run = {\n        /**\n         * @description Run a specific command. For example, `\"open -a 'Mission Control'\"`.\n         */\n        run: string;\n      };\n\n      type MouseWheelScrollUpWithDistance = {\n        /**\n         * @description Mouse: Wheel: Scroll up a certain distance.\n         */\n        \"mouse.wheel.scrollUp\": Scheme.Scrolling.Distance;\n      };\n\n      type MouseWheelScrollDownWithDistance = {\n        /**\n         * @description Mouse: Wheel: Scroll down a certain distance.\n         */\n        \"mouse.wheel.scrollDown\": Scheme.Scrolling.Distance;\n      };\n\n      type MouseWheelScrollLeftWithDistance = {\n        /**\n         * @description Mouse: Wheel: Scroll left a certain distance.\n         */\n        \"mouse.wheel.scrollLeft\": Scheme.Scrolling.Distance;\n      };\n\n      type MouseWheelScrollRightWithDistance = {\n        /**\n         * @description Mouse: Wheel: Scroll right a certain distance.\n         */\n        \"mouse.wheel.scrollRight\": Scheme.Scrolling.Distance;\n      };\n\n      type KeyPress = {\n        /**\n         * @description Keyboard: Keyboard shortcut.\n         */\n        keyPress: Array<Key>;\n      };\n\n      /**\n       * @description Scroll direction.\n       */\n      type ScrollDirection = \"up\" | \"down\" | \"left\" | \"right\";\n\n      type Key =\n        | \"enter\"\n        | \"tab\"\n        | \"space\"\n        | \"delete\"\n        | \"escape\"\n        | \"command\"\n        | \"shift\"\n        | \"capsLock\"\n        | \"option\"\n        | \"control\"\n        | \"commandRight\"\n        | \"shiftRight\"\n        | \"optionRight\"\n        | \"controlRight\"\n        | \"arrowLeft\"\n        | \"arrowRight\"\n        | \"arrowDown\"\n        | \"arrowUp\"\n        | \"home\"\n        | \"pageUp\"\n        | \"backspace\"\n        | \"end\"\n        | \"pageDown\"\n        | \"f1\"\n        | \"f2\"\n        | \"f3\"\n        | \"f4\"\n        | \"f5\"\n        | \"f6\"\n        | \"f7\"\n        | \"f8\"\n        | \"f9\"\n        | \"f10\"\n        | \"f11\"\n        | \"f12\"\n        | \"a\"\n        | \"b\"\n        | \"c\"\n        | \"d\"\n        | \"e\"\n        | \"f\"\n        | \"g\"\n        | \"h\"\n        | \"i\"\n        | \"j\"\n        | \"k\"\n        | \"l\"\n        | \"m\"\n        | \"n\"\n        | \"o\"\n        | \"p\"\n        | \"q\"\n        | \"r\"\n        | \"s\"\n        | \"t\"\n        | \"u\"\n        | \"v\"\n        | \"w\"\n        | \"x\"\n        | \"y\"\n        | \"z\"\n        | \"0\"\n        | \"1\"\n        | \"2\"\n        | \"3\"\n        | \"4\"\n        | \"5\"\n        | \"6\"\n        | \"7\"\n        | \"8\"\n        | \"9\"\n        | \"=\"\n        | \"-\"\n        | \";\"\n        | \"'\"\n        | \",\"\n        | \".\"\n        | \"/\"\n        | \"\\\\\"\n        | \"`\"\n        | \"[\"\n        | \"]\"\n        | \"numpadPlus\"\n        | \"numpadMinus\"\n        | \"numpadMultiply\"\n        | \"numpadDivide\"\n        | \"numpadEnter\"\n        | \"numpadEquals\"\n        | \"numpadDecimal\"\n        | \"numpadClear\"\n        | \"numpad0\"\n        | \"numpad1\"\n        | \"numpad2\"\n        | \"numpad3\"\n        | \"numpad4\"\n        | \"numpad5\"\n        | \"numpad6\"\n        | \"numpad7\"\n        | \"numpad8\"\n        | \"numpad9\";\n    }\n\n    type UniversalBackForward =\n      | boolean\n      | UniversalBackForward.BackOnly\n      | UniversalBackForward.ForwardOnly;\n\n    namespace UniversalBackForward {\n      /**\n       * @description Enable universal back only.\n       */\n      type BackOnly = \"backOnly\";\n\n      /**\n       * @description Enable universal forward only.\n       */\n      type ForwardOnly = \"forwardOnly\";\n    }\n\n    type ClickDebouncing = {\n      /**\n       * @description The time period in which rapid clicks are ignored.\n       */\n      timeout?: Int;\n\n      /**\n       * @description If the value is true, the timer will be reset on mouse up.\n       */\n      resetTimerOnMouseUp?: boolean;\n\n      /**\n       * @description Buttons to debounce.\n       */\n      buttons?: PhysicalButton[];\n    };\n\n    type Gesture = {\n      /**\n       * @title Enable gesture button\n       * @description If the value is true, the gesture button feature is enabled.\n       * @default false\n       */\n      enabled?: boolean;\n\n      /**\n       * @title Trigger\n       * @description Choose the mouse button and modifier keys used to activate gestures.\n       */\n      trigger?: Gesture.Trigger;\n\n      /**\n       * @title Button\n       * @description Deprecated. Use trigger instead.\n       * @deprecated\n       */\n      button?: PhysicalButton;\n\n      /**\n       * @title Threshold\n       * @description The distance in pixels that must be dragged before triggering a gesture.\n       * @default 50\n       * @minimum 20\n       * @maximum 200\n       */\n      threshold?: Int;\n\n      /**\n       * @title Dead zone\n       * @description The tolerance in pixels for the non-dominant axis to prevent accidental gestures.\n       * @default 40\n       * @minimum 0\n       * @maximum 100\n       */\n      deadZone?: Int;\n\n      /**\n       * @title Cooldown\n       * @description The cooldown period in milliseconds between gestures to prevent double-triggering.\n       * @default 500\n       * @minimum 0\n       * @maximum 2000\n       */\n      cooldownMs?: Int;\n\n      /**\n       * @title Gesture actions\n       * @description Actions to trigger for each gesture direction.\n       */\n      actions?: Gesture.Actions;\n    };\n\n    namespace Gesture {\n      type Trigger = {\n        /**\n         * @title Button number\n         * @description The button number. See https://developer.apple.com/documentation/coregraphics/cgmousebutton\n         */\n        button: Mapping.Button;\n\n        /**\n         * @description Indicates if the command modifier key should be pressed.\n         */\n        command?: boolean;\n\n        /**\n         * @description Indicates if the shift modifier key should be pressed.\n         */\n        shift?: boolean;\n\n        /**\n         * @description Indicates if the option modifier key should be pressed.\n         */\n        option?: boolean;\n\n        /**\n         * @description Indicates if the control modifier key should be pressed.\n         */\n        control?: boolean;\n      };\n\n      type Actions = {\n        /**\n         * @title Swipe left action\n         * @description Action to trigger when dragging left.\n         * @default \"missionControl.spaceLeft\"\n         */\n        left?: GestureAction;\n\n        /**\n         * @title Swipe right action\n         * @description Action to trigger when dragging right.\n         * @default \"missionControl.spaceRight\"\n         */\n        right?: GestureAction;\n\n        /**\n         * @title Swipe up action\n         * @description Action to trigger when dragging up.\n         * @default \"missionControl\"\n         */\n        up?: GestureAction;\n\n        /**\n         * @title Swipe down action\n         * @description Action to trigger when dragging down.\n         * @default \"appExpose\"\n         */\n        down?: GestureAction;\n      };\n\n      type GestureAction =\n        | \"none\"\n        | \"missionControl.spaceLeft\"\n        | \"missionControl.spaceRight\"\n        | \"missionControl\"\n        | \"appExpose\"\n        | \"showDesktop\"\n        | \"launchpad\";\n    }\n  }\n}\n"
  },
  {
    "path": "Documentation/Configuration.json",
    "content": "{\n  \"$ref\": \"#/definitions/Configuration\",\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"definitions\": {\n    \"Auxiliary\": {\n      \"const\": 2,\n      \"description\": \"Auxiliary button, usually the wheel button or the middle button.\",\n      \"type\": \"number\"\n    },\n    \"Back\": {\n      \"const\": 3,\n      \"description\": \"Forth button, typically the back button.\",\n      \"type\": \"number\"\n    },\n    \"Configuration\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"$schema\": {\n          \"type\": \"string\"\n        },\n        \"schemes\": {\n          \"description\": \"A scheme is a collection of settings that are activated in specified circumstances.\",\n          \"examples\": [\n            {\n              \"if\": {\n                \"device\": {\n                  \"category\": \"mouse\"\n                }\n              },\n              \"scrolling\": {\n                \"reverse\": \"vertical\"\n              }\n            }\n          ],\n          \"items\": {\n            \"$ref\": \"#/definitions/Scheme\"\n          },\n          \"title\": \"Schemes\",\n          \"type\": \"array\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Forward\": {\n      \"const\": 4,\n      \"description\": \"Fifth button, typically the forward button.\",\n      \"type\": \"number\"\n    },\n    \"HexString\": {\n      \"pattern\": \"^0x[0-9a-fA-F]+$\",\n      \"type\": \"string\"\n    },\n    \"Int\": {\n      \"type\": \"number\"\n    },\n    \"IntString\": {\n      \"pattern\": \"^\\\\d+$\",\n      \"type\": \"string\"\n    },\n    \"PhysicalButton\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Primary\"\n        },\n        {\n          \"$ref\": \"#/definitions/Secondary\"\n        },\n        {\n          \"$ref\": \"#/definitions/Auxiliary\"\n        },\n        {\n          \"$ref\": \"#/definitions/Back\"\n        },\n        {\n          \"$ref\": \"#/definitions/Forward\"\n        },\n        {\n          \"type\": \"number\"\n        }\n      ]\n    },\n    \"Primary\": {\n      \"const\": 0,\n      \"description\": \"Primary button, usually the left button.\",\n      \"type\": \"number\"\n    },\n    \"Scheme\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"buttons\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons\",\n          \"description\": \"Customize the buttons behavior.\",\n          \"title\": \"Buttons settings\"\n        },\n        \"if\": {\n          \"$ref\": \"#/definitions/SingleValueOrArray%3CScheme.If%3E\",\n          \"description\": \"This value can be a single condition or an array. A scheme is activated if at least one of the conditions is met.\",\n          \"title\": \"Scheme activation conditions\"\n        },\n        \"pointer\": {\n          \"$ref\": \"#/definitions/Scheme.Pointer\",\n          \"description\": \"Customize the pointer acceleration and speed.\",\n          \"title\": \"Pointer settings\"\n        },\n        \"scrolling\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling\",\n          \"description\": \"Customize the scrolling behavior.\",\n          \"title\": \"Scrolling settings\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"autoScroll\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.AutoScroll\",\n          \"description\": \"Click or hold a mouse button, then move the pointer to continuously scroll like the Windows middle-button autoscroll behavior.\",\n          \"title\": \"Auto scroll\"\n        },\n        \"clickDebouncing\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.ClickDebouncing\",\n          \"description\": \"Ignore rapid clicks with a certain time period.\",\n          \"title\": \"Debounce button clicks\"\n        },\n        \"gesture\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture\",\n          \"description\": \"Press and hold a button while dragging to trigger gestures like switching desktop spaces or opening Mission Control.\",\n          \"title\": \"Gesture button\"\n        },\n        \"mappings\": {\n          \"description\": \"Assign actions to buttons.\",\n          \"items\": {\n            \"$ref\": \"#/definitions/Scheme.Buttons.Mapping\"\n          },\n          \"title\": \"Button mappings\",\n          \"type\": \"array\"\n        },\n        \"switchPrimaryButtonAndSecondaryButtons\": {\n          \"default\": false,\n          \"description\": \"If the value is true, the primary button will be the right button and the secondary button will be the left button.\",\n          \"title\": \"Switch primary and secondary buttons\",\n          \"type\": \"boolean\"\n        },\n        \"universalBackForward\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.UniversalBackForward\",\n          \"default\": false,\n          \"description\": \"If the value is true, the back and forward side buttons will be enabled in Safari and some other apps that do not handle these side buttons correctly. If the value is \\\"backOnly\\\" or \\\"forwardOnly\\\", only universal back or universal forward will be enabled.\",\n          \"title\": \"Universal back and forward\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.AutoScroll\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"enabled\": {\n          \"default\": false,\n          \"description\": \"Indicates if auto scroll is enabled.\",\n          \"type\": \"boolean\"\n        },\n        \"mode\": {\n          \"$ref\": \"#/definitions/SingleValueOrArray%3CScheme.Buttons.AutoScroll.Mode%3E\",\n          \"description\": \"Use \\\\\\\"toggle\\\\\\\" to click once and move until clicking again, \\\\\\\"hold\\\\\\\" to scroll only while the trigger stays pressed, or provide both to support both behaviors.\",\n          \"title\": \"Activation mode\"\n        },\n        \"preserveNativeMiddleClick\": {\n          \"default\": false,\n          \"description\": \"If true, a plain middle click on a pressable element such as a link will keep its native behavior when possible.\",\n          \"type\": \"boolean\"\n        },\n        \"speed\": {\n          \"default\": 1,\n          \"description\": \"Adjust the auto scroll speed multiplier.\",\n          \"type\": \"number\"\n        },\n        \"trigger\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.AutoScroll.Trigger\",\n          \"description\": \"Choose the mouse button and modifier keys used to activate auto scroll.\",\n          \"title\": \"Trigger\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.AutoScroll.Hold\": {\n      \"const\": \"hold\",\n      \"description\": \"Auto scroll is active only while the trigger button remains pressed.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.AutoScroll.Mode\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.AutoScroll.Toggle\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.AutoScroll.Hold\"\n        }\n      ]\n    },\n    \"Scheme.Buttons.AutoScroll.Toggle\": {\n      \"const\": \"toggle\",\n      \"description\": \"Click once to enter auto scroll and click again to exit.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.AutoScroll.Trigger\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"button\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Button\",\n          \"description\": \"The button number. See https://developer.apple.com/documentation/coregraphics/cgmousebutton\",\n          \"title\": \"Button number\"\n        },\n        \"command\": {\n          \"description\": \"Indicates if the command modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        },\n        \"control\": {\n          \"description\": \"Indicates if the control modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        },\n        \"option\": {\n          \"description\": \"Indicates if the option modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        },\n        \"shift\": {\n          \"description\": \"Indicates if the shift modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        }\n      },\n      \"required\": [\n        \"button\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.ClickDebouncing\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"buttons\": {\n          \"description\": \"Buttons to debounce.\",\n          \"items\": {\n            \"$ref\": \"#/definitions/PhysicalButton\"\n          },\n          \"type\": \"array\"\n        },\n        \"resetTimerOnMouseUp\": {\n          \"description\": \"If the value is true, the timer will be reset on mouse up.\",\n          \"type\": \"boolean\"\n        },\n        \"timeout\": {\n          \"$ref\": \"#/definitions/Int\",\n          \"description\": \"The time period in which rapid clicks are ignored.\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Gesture\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"actions\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture.Actions\",\n          \"description\": \"Actions to trigger for each gesture direction.\",\n          \"title\": \"Gesture actions\"\n        },\n        \"button\": {\n          \"$ref\": \"#/definitions/PhysicalButton\",\n          \"deprecated\": true,\n          \"description\": \"Deprecated. Use trigger instead.\",\n          \"title\": \"Button\"\n        },\n        \"cooldownMs\": {\n          \"$ref\": \"#/definitions/Int\",\n          \"default\": 500,\n          \"description\": \"The cooldown period in milliseconds between gestures to prevent double-triggering.\",\n          \"maximum\": 2000,\n          \"minimum\": 0,\n          \"title\": \"Cooldown\"\n        },\n        \"deadZone\": {\n          \"$ref\": \"#/definitions/Int\",\n          \"default\": 40,\n          \"description\": \"The tolerance in pixels for the non-dominant axis to prevent accidental gestures.\",\n          \"maximum\": 100,\n          \"minimum\": 0,\n          \"title\": \"Dead zone\"\n        },\n        \"enabled\": {\n          \"default\": false,\n          \"description\": \"If the value is true, the gesture button feature is enabled.\",\n          \"title\": \"Enable gesture button\",\n          \"type\": \"boolean\"\n        },\n        \"threshold\": {\n          \"$ref\": \"#/definitions/Int\",\n          \"default\": 50,\n          \"description\": \"The distance in pixels that must be dragged before triggering a gesture.\",\n          \"maximum\": 200,\n          \"minimum\": 20,\n          \"title\": \"Threshold\"\n        },\n        \"trigger\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture.Trigger\",\n          \"description\": \"Choose the mouse button and modifier keys used to activate gestures.\",\n          \"title\": \"Trigger\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Gesture.Actions\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"down\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture.GestureAction\",\n          \"default\": \"appExpose\",\n          \"description\": \"Action to trigger when dragging down.\",\n          \"title\": \"Swipe down action\"\n        },\n        \"left\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture.GestureAction\",\n          \"default\": \"missionControl.spaceLeft\",\n          \"description\": \"Action to trigger when dragging left.\",\n          \"title\": \"Swipe left action\"\n        },\n        \"right\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture.GestureAction\",\n          \"default\": \"missionControl.spaceRight\",\n          \"description\": \"Action to trigger when dragging right.\",\n          \"title\": \"Swipe right action\"\n        },\n        \"up\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Gesture.GestureAction\",\n          \"default\": \"missionControl\",\n          \"description\": \"Action to trigger when dragging up.\",\n          \"title\": \"Swipe up action\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Gesture.GestureAction\": {\n      \"enum\": [\n        \"none\",\n        \"missionControl.spaceLeft\",\n        \"missionControl.spaceRight\",\n        \"missionControl\",\n        \"appExpose\",\n        \"showDesktop\",\n        \"launchpad\"\n      ],\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Gesture.Trigger\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"button\": {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Button\",\n          \"description\": \"The button number. See https://developer.apple.com/documentation/coregraphics/cgmousebutton\",\n          \"title\": \"Button number\"\n        },\n        \"command\": {\n          \"description\": \"Indicates if the command modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        },\n        \"control\": {\n          \"description\": \"Indicates if the control modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        },\n        \"option\": {\n          \"description\": \"Indicates if the option modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        },\n        \"shift\": {\n          \"description\": \"Indicates if the shift modifier key should be pressed.\",\n          \"type\": \"boolean\"\n        }\n      },\n      \"required\": [\n        \"button\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping\": {\n      \"anyOf\": [\n        {\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"action\": {\n              \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Action\",\n              \"title\": \"Action\"\n            },\n            \"button\": {\n              \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Button\",\n              \"description\": \"The button number. See https://developer.apple.com/documentation/coregraphics/cgmousebutton\",\n              \"title\": \"Button number\"\n            },\n            \"command\": {\n              \"description\": \"Indicates if the command modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            },\n            \"control\": {\n              \"description\": \"Indicates if the control modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            },\n            \"hold\": {\n              \"description\": \"Indicates if keyboard shortcut actions should stay pressed while the button is held. When enabled, LinearMouse sends key down on button press and key up on button release instead of repeating the shortcut.\",\n              \"type\": \"boolean\"\n            },\n            \"option\": {\n              \"description\": \"Indicates if the option modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            },\n            \"repeat\": {\n              \"description\": \"Indicates if key repeat is enabled. If the value is true, the action will be repeatedly executed when the button is hold according to the key repeat settings in System Settings.\",\n              \"type\": \"boolean\"\n            },\n            \"shift\": {\n              \"description\": \"Indicates if the shift modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            }\n          },\n          \"required\": [\n            \"button\"\n          ],\n          \"type\": \"object\"\n        },\n        {\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"action\": {\n              \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Action\",\n              \"title\": \"Action\"\n            },\n            \"command\": {\n              \"description\": \"Indicates if the command modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            },\n            \"control\": {\n              \"description\": \"Indicates if the control modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            },\n            \"option\": {\n              \"description\": \"Indicates if the option modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            },\n            \"scroll\": {\n              \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.ScrollDirection\",\n              \"description\": \"Map scroll events to specific actions.\",\n              \"title\": \"Scroll direction\"\n            },\n            \"shift\": {\n              \"description\": \"Indicates if the shift modifier key should be pressed.\",\n              \"type\": \"boolean\"\n            }\n          },\n          \"required\": [\n            \"scroll\"\n          ],\n          \"type\": \"object\"\n        }\n      ]\n    },\n    \"Scheme.Buttons.Mapping.Action\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.SimpleAction\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Run\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollUpWithDistance\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollDownWithDistance\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollLeftWithDistance\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollRightWithDistance\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.KeyPress\"\n        }\n      ]\n    },\n    \"Scheme.Buttons.Mapping.AppExpose\": {\n      \"const\": \"appExpose\",\n      \"description\": \"Application windows.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.Auto\": {\n      \"const\": \"auto\",\n      \"description\": \"Do not modify the button behavior.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.Button\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/PhysicalButton\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.LogitechControlButton\"\n        }\n      ]\n    },\n    \"Scheme.Buttons.Mapping.DisplayBrightnessDown\": {\n      \"const\": \"display.brightnessDown\",\n      \"description\": \"Display: Brightness down.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.DisplayBrightnessUp\": {\n      \"const\": \"display.brightnessUp\",\n      \"description\": \"Display: Brightness up.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.Key\": {\n      \"enum\": [\n        \"enter\",\n        \"tab\",\n        \"space\",\n        \"delete\",\n        \"escape\",\n        \"command\",\n        \"shift\",\n        \"capsLock\",\n        \"option\",\n        \"control\",\n        \"commandRight\",\n        \"shiftRight\",\n        \"optionRight\",\n        \"controlRight\",\n        \"arrowLeft\",\n        \"arrowRight\",\n        \"arrowDown\",\n        \"arrowUp\",\n        \"home\",\n        \"pageUp\",\n        \"backspace\",\n        \"end\",\n        \"pageDown\",\n        \"f1\",\n        \"f2\",\n        \"f3\",\n        \"f4\",\n        \"f5\",\n        \"f6\",\n        \"f7\",\n        \"f8\",\n        \"f9\",\n        \"f10\",\n        \"f11\",\n        \"f12\",\n        \"a\",\n        \"b\",\n        \"c\",\n        \"d\",\n        \"e\",\n        \"f\",\n        \"g\",\n        \"h\",\n        \"i\",\n        \"j\",\n        \"k\",\n        \"l\",\n        \"m\",\n        \"n\",\n        \"o\",\n        \"p\",\n        \"q\",\n        \"r\",\n        \"s\",\n        \"t\",\n        \"u\",\n        \"v\",\n        \"w\",\n        \"x\",\n        \"y\",\n        \"z\",\n        \"0\",\n        \"1\",\n        \"2\",\n        \"3\",\n        \"4\",\n        \"5\",\n        \"6\",\n        \"7\",\n        \"8\",\n        \"9\",\n        \"=\",\n        \"-\",\n        \";\",\n        \"'\",\n        \",\",\n        \".\",\n        \"/\",\n        \"\\\\\",\n        \"`\",\n        \"[\",\n        \"]\",\n        \"numpadPlus\",\n        \"numpadMinus\",\n        \"numpadMultiply\",\n        \"numpadDivide\",\n        \"numpadEnter\",\n        \"numpadEquals\",\n        \"numpadDecimal\",\n        \"numpadClear\",\n        \"numpad0\",\n        \"numpad1\",\n        \"numpad2\",\n        \"numpad3\",\n        \"numpad4\",\n        \"numpad5\",\n        \"numpad6\",\n        \"numpad7\",\n        \"numpad8\",\n        \"numpad9\"\n      ],\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.KeyPress\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"keyPress\": {\n          \"description\": \"Keyboard: Keyboard shortcut.\",\n          \"items\": {\n            \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Key\"\n          },\n          \"type\": \"array\"\n        }\n      },\n      \"required\": [\n        \"keyPress\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.KeyboardBrightnessDown\": {\n      \"const\": \"keyboard.brightnessDown\",\n      \"description\": \"Keyboard: Brightness down.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.KeyboardBrightnessUp\": {\n      \"const\": \"keyboard.brightnessUp\",\n      \"description\": \"Keyboard: Brightness up.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.Launchpad\": {\n      \"const\": \"launchpad\",\n      \"description\": \"Launchpad.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.LogitechControlButton\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"controlID\": {\n          \"$ref\": \"#/definitions/Int\",\n          \"description\": \"Logitech control ID (CID).\"\n        },\n        \"kind\": {\n          \"const\": \"logitechControl\",\n          \"description\": \"Logitech control button identifier.\",\n          \"type\": \"string\"\n        },\n        \"productID\": {\n          \"anyOf\": [\n            {\n              \"$ref\": \"#/definitions/HexString\"\n            },\n            {\n              \"$ref\": \"#/definitions/Int\"\n            }\n          ],\n          \"description\": \"Match a specific Logitech device product ID when needed.\"\n        },\n        \"serialNumber\": {\n          \"description\": \"Match a specific Logitech device serial number when needed.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"kind\",\n        \"controlID\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.LookUpAndDataDetectors\": {\n      \"const\": \"lookUpAndDataDetectors\",\n      \"description\": \"Look up & data detectors.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaFastForward\": {\n      \"const\": \"media.fastForward\",\n      \"description\": \"Media: Fast forward.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaMute\": {\n      \"const\": \"media.mute\",\n      \"description\": \"Media: Toggle mute.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaNext\": {\n      \"const\": \"media.next\",\n      \"description\": \"Media: Next.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaPlayPause\": {\n      \"const\": \"media.playPause\",\n      \"description\": \"Media: Play / pause.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaPrevious\": {\n      \"const\": \"media.previous\",\n      \"description\": \"Media: Previous.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaRewind\": {\n      \"const\": \"media.rewind\",\n      \"description\": \"Media: Rewind.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaVolumeDown\": {\n      \"const\": \"media.volumeDown\",\n      \"description\": \"Media: Volume down.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MediaVolumeUp\": {\n      \"const\": \"media.volumeUp\",\n      \"description\": \"Media: Volume up.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MissionControl\": {\n      \"const\": \"missionControl\",\n      \"description\": \"Mission Control.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MissionControlSpaceLeft\": {\n      \"const\": \"missionControl.spaceLeft\",\n      \"description\": \"Mission Control: Move left a space.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MissionControlSpaceRight\": {\n      \"const\": \"missionControl.spaceRight\",\n      \"description\": \"Mission Control: Move right a space.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseButtonBack\": {\n      \"const\": \"mouse.button.back\",\n      \"description\": \"Mouse: Button: Act as back button.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseButtonForward\": {\n      \"const\": \"mouse.button.forward\",\n      \"description\": \"Mouse: Button: Act as forward button.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseButtonLeft\": {\n      \"const\": \"mouse.button.left\",\n      \"description\": \"Mouse: Button: Act as left button.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseButtonMiddle\": {\n      \"const\": \"mouse.button.middle\",\n      \"description\": \"Mouse: Button: Act as middle button.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseButtonRight\": {\n      \"const\": \"mouse.button.right\",\n      \"description\": \"Mouse: Button: Act as right button.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollDown\": {\n      \"const\": \"mouse.wheel.scrollDown\",\n      \"description\": \"Mouse: Wheel: Scroll down.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollDownWithDistance\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"mouse.wheel.scrollDown\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\",\n          \"description\": \"Mouse: Wheel: Scroll down a certain distance.\"\n        }\n      },\n      \"required\": [\n        \"mouse.wheel.scrollDown\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollLeft\": {\n      \"const\": \"mouse.wheel.scrollLeft\",\n      \"description\": \"Mouse: Wheel: Scroll left.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollLeftWithDistance\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"mouse.wheel.scrollLeft\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\",\n          \"description\": \"Mouse: Wheel: Scroll left a certain distance.\"\n        }\n      },\n      \"required\": [\n        \"mouse.wheel.scrollLeft\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollRight\": {\n      \"const\": \"mouse.wheel.scrollRight\",\n      \"description\": \"Mouse: Wheel: Scroll right.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollRightWithDistance\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"mouse.wheel.scrollRight\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\",\n          \"description\": \"Mouse: Wheel: Scroll right a certain distance.\"\n        }\n      },\n      \"required\": [\n        \"mouse.wheel.scrollRight\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollUp\": {\n      \"const\": \"mouse.wheel.scrollUp\",\n      \"description\": \"Mouse: Wheel: Scroll up.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.MouseWheelScrollUpWithDistance\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"mouse.wheel.scrollUp\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\",\n          \"description\": \"Mouse: Wheel: Scroll up a certain distance.\"\n        }\n      },\n      \"required\": [\n        \"mouse.wheel.scrollUp\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.None\": {\n      \"const\": \"none\",\n      \"description\": \"Prevent the button events.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.Run\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"run\": {\n          \"description\": \"Run a specific command. For example, `\\\"open -a 'Mission Control'\\\"`.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"run\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Buttons.Mapping.ScrollDirection\": {\n      \"description\": \"Scroll direction.\",\n      \"enum\": [\n        \"up\",\n        \"down\",\n        \"left\",\n        \"right\"\n      ],\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.ShowDesktop\": {\n      \"const\": \"showDesktop\",\n      \"description\": \"Show desktop.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.Mapping.SimpleAction\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Auto\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.None\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MissionControlSpaceLeft\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MissionControlSpaceRight\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MissionControl\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.AppExpose\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.Launchpad\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.ShowDesktop\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.LookUpAndDataDetectors\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.SmartZoom\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.DisplayBrightnessUp\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.DisplayBrightnessDown\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaVolumeUp\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaVolumeDown\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaMute\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaPlayPause\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaNext\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaPrevious\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaFastForward\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MediaRewind\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.KeyboardBrightnessUp\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.KeyboardBrightnessDown\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollUp\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollDown\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollLeft\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseWheelScrollRight\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseButtonLeft\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseButtonMiddle\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseButtonRight\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseButtonBack\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.Mapping.MouseButtonForward\"\n        }\n      ]\n    },\n    \"Scheme.Buttons.Mapping.SmartZoom\": {\n      \"const\": \"smartZoom\",\n      \"description\": \"Smart zoom.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.UniversalBackForward\": {\n      \"anyOf\": [\n        {\n          \"type\": \"boolean\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.UniversalBackForward.BackOnly\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.UniversalBackForward.ForwardOnly\"\n        }\n      ]\n    },\n    \"Scheme.Buttons.UniversalBackForward.BackOnly\": {\n      \"const\": \"backOnly\",\n      \"description\": \"Enable universal back only.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Buttons.UniversalBackForward.ForwardOnly\": {\n      \"const\": \"forwardOnly\",\n      \"description\": \"Enable universal forward only.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.If\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"app\": {\n          \"description\": \"Match apps by providing the bundle ID. For example, `com.apple.Safari`.\",\n          \"title\": \"App\",\n          \"type\": \"string\"\n        },\n        \"device\": {\n          \"$ref\": \"#/definitions/Scheme.If.Device\",\n          \"description\": \"Match one or more devices. If not provided, the scheme is activated on all devices.\",\n          \"title\": \"Device\"\n        },\n        \"display\": {\n          \"description\": \"Match displays by providing the display name. For example, `DELL P2415Q`.\",\n          \"title\": \"Display name\",\n          \"type\": \"string\"\n        },\n        \"groupApp\": {\n          \"description\": \"Match apps by providing the bundle ID of the process group. For example, `org.polymc.PolyMC`.\",\n          \"title\": \"Group app\",\n          \"type\": \"string\"\n        },\n        \"parentApp\": {\n          \"description\": \"Match apps by providing the bundle ID of the parent process. For example, `org.polymc.PolyMC`.\",\n          \"title\": \"Parent app\",\n          \"type\": \"string\"\n        },\n        \"processName\": {\n          \"description\": \"Match by the executable file name of the frontmost process (from NSRunningApplication.executableURL.lastPathComponent). Case-sensitive.\",\n          \"title\": \"Process name\",\n          \"type\": \"string\"\n        },\n        \"processPath\": {\n          \"description\": \"Match by the absolute executable path of the frontmost process (from NSRunningApplication.executableURL.path). Case-sensitive.\",\n          \"title\": \"Process path\",\n          \"type\": \"string\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.If.Category\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.If.Mouse\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.If.Trackpad\"\n        }\n      ]\n    },\n    \"Scheme.If.Device\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"category\": {\n          \"$ref\": \"#/definitions/SingleValueOrArray%3CScheme.If.Category%3E\",\n          \"description\": \"The category of the devices.\",\n          \"title\": \"Category\"\n        },\n        \"productID\": {\n          \"anyOf\": [\n            {\n              \"$ref\": \"#/definitions/HexString\"\n            },\n            {\n              \"$ref\": \"#/definitions/Int\"\n            }\n          ],\n          \"description\": \"The product ID of the devices.\",\n          \"examples\": [\n            \"0xA123\"\n          ],\n          \"title\": \"Product ID\"\n        },\n        \"productName\": {\n          \"description\": \"The product name of the devices.\",\n          \"title\": \"Product name\",\n          \"type\": \"string\"\n        },\n        \"serialNumber\": {\n          \"description\": \"The serial number of the devices.\",\n          \"title\": \"Serial number\",\n          \"type\": \"string\"\n        },\n        \"vendorID\": {\n          \"anyOf\": [\n            {\n              \"$ref\": \"#/definitions/HexString\"\n            },\n            {\n              \"$ref\": \"#/definitions/Int\"\n            }\n          ],\n          \"description\": \"The vendor ID of the devices.\",\n          \"examples\": [\n            \"0xA123\"\n          ],\n          \"title\": \"Vendor ID\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.If.Mouse\": {\n      \"const\": \"mouse\",\n      \"description\": \"Match mouse devices.\",\n      \"title\": \"Mouse\",\n      \"type\": \"string\"\n    },\n    \"Scheme.If.Trackpad\": {\n      \"const\": \"trackpad\",\n      \"description\": \"Match trackpad devices.\",\n      \"title\": \"Trackpad\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Pointer\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"acceleration\": {\n          \"anyOf\": [\n            {\n              \"type\": \"number\"\n            },\n            {\n              \"$ref\": \"#/definitions/Unset\"\n            }\n          ],\n          \"description\": \"A number to set acceleration, or \\\"unset\\\" to restore system default. If omitted, the previous/merged value applies.\",\n          \"maximum\": 20,\n          \"minimum\": 0,\n          \"title\": \"Pointer acceleration\"\n        },\n        \"disableAcceleration\": {\n          \"default\": false,\n          \"description\": \"If the value is true, the pointer acceleration will be disabled and acceleration and speed will not take effect.\",\n          \"title\": \"Disable pointer acceleration\",\n          \"type\": \"boolean\"\n        },\n        \"redirectsToScroll\": {\n          \"default\": false,\n          \"description\": \"If the value is true, pointer movements will be redirected to scroll events.\",\n          \"title\": \"Redirects to scroll\",\n          \"type\": \"boolean\"\n        },\n        \"speed\": {\n          \"anyOf\": [\n            {\n              \"type\": \"number\"\n            },\n            {\n              \"$ref\": \"#/definitions/Unset\"\n            }\n          ],\n          \"description\": \"A number to set speed, or \\\"unset\\\" to restore device default. If omitted, the previous/merged value applies.\",\n          \"maximum\": 1,\n          \"title\": \"Pointer speed\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"acceleration\": {\n          \"anyOf\": [\n            {\n              \"type\": \"number\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"horizontal\": {\n                  \"type\": \"number\"\n                },\n                \"vertical\": {\n                  \"type\": \"number\"\n                }\n              },\n              \"type\": \"object\"\n            }\n          ],\n          \"default\": 1,\n          \"description\": \"The scrolling acceleration.\"\n        },\n        \"distance\": {\n          \"anyOf\": [\n            {\n              \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"horizontal\": {\n                  \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\"\n                },\n                \"vertical\": {\n                  \"$ref\": \"#/definitions/Scheme.Scrolling.Distance\"\n                }\n              },\n              \"type\": \"object\"\n            }\n          ],\n          \"description\": \"The distance after rolling the wheel.\",\n          \"title\": \"Scroll distance\"\n        },\n        \"modifiers\": {\n          \"anyOf\": [\n            {\n              \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"horizontal\": {\n                  \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers\"\n                },\n                \"vertical\": {\n                  \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers\"\n                }\n              },\n              \"type\": \"object\"\n            }\n          ],\n          \"title\": \"Modifier keys settings\"\n        },\n        \"reverse\": {\n          \"anyOf\": [\n            {\n              \"type\": \"boolean\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"horizontal\": {\n                  \"type\": \"boolean\"\n                },\n                \"vertical\": {\n                  \"type\": \"boolean\"\n                }\n              },\n              \"type\": \"object\"\n            }\n          ],\n          \"title\": \"Reverse scrolling\"\n        },\n        \"smoothed\": {\n          \"anyOf\": [\n            {\n              \"$ref\": \"#/definitions/Scheme.Scrolling.Smoothed\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"horizontal\": {\n                  \"$ref\": \"#/definitions/Scheme.Scrolling.Smoothed\"\n                },\n                \"vertical\": {\n                  \"$ref\": \"#/definitions/Scheme.Scrolling.Smoothed\"\n                }\n              },\n              \"type\": \"object\"\n            }\n          ],\n          \"description\": \"Use a preset curve or fine-tune response, speed, acceleration, and inertia.\",\n          \"title\": \"Smoothed scrolling\"\n        },\n        \"speed\": {\n          \"anyOf\": [\n            {\n              \"type\": \"number\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"horizontal\": {\n                  \"type\": \"number\"\n                },\n                \"vertical\": {\n                  \"type\": \"number\"\n                }\n              },\n              \"type\": \"object\"\n            }\n          ],\n          \"default\": 0,\n          \"description\": \"The scrolling speed.\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Auto\": {\n      \"const\": \"auto\",\n      \"description\": \"The scrolling distance will not be modified.\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Scrolling.Distance\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Auto\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Distance.Line\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Distance.Pixel\"\n        }\n      ]\n    },\n    \"Scheme.Scrolling.Distance.Line\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Int\"\n        },\n        {\n          \"$ref\": \"#/definitions/IntString\"\n        }\n      ],\n      \"description\": \"The scrolling distance in lines.\"\n    },\n    \"Scheme.Scrolling.Distance.Pixel\": {\n      \"description\": \"The scrolling distance in pixels.\",\n      \"pattern\": \"^\\\\d[1-9]*(\\\\.\\\\d+)?px\",\n      \"type\": \"string\"\n    },\n    \"Scheme.Scrolling.Modifiers\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"command\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Action\",\n          \"description\": \"The action when command key is pressed.\"\n        },\n        \"control\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Action\",\n          \"description\": \"The action when control key is pressed.\"\n        },\n        \"option\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Action\",\n          \"description\": \"The action when option key is pressed.\"\n        },\n        \"shift\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Action\",\n          \"description\": \"The action when shift key is pressed.\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.Action\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.None\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Auto\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Ignore\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.PreventDefault\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.AlterOrientation\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.ChangeSpeed\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.Zoom\"\n        },\n        {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Modifiers.PinchZoom\"\n        }\n      ]\n    },\n    \"Scheme.Scrolling.Modifiers.AlterOrientation\": {\n      \"additionalProperties\": false,\n      \"description\": \"Alter the scrolling orientation from vertical to horizontal or vice versa.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"alterOrientation\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.Auto\": {\n      \"additionalProperties\": false,\n      \"description\": \"Default action.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"auto\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.ChangeSpeed\": {\n      \"additionalProperties\": false,\n      \"description\": \"Scale the scrolling speed.\",\n      \"properties\": {\n        \"scale\": {\n          \"description\": \"The factor to scale the scrolling speed.\",\n          \"type\": \"number\"\n        },\n        \"type\": {\n          \"const\": \"changeSpeed\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\",\n        \"scale\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.Ignore\": {\n      \"additionalProperties\": false,\n      \"description\": \"Ignore modifier.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"ignore\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.None\": {\n      \"additionalProperties\": false,\n      \"deprecated\": true,\n      \"description\": \"Default action.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"none\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.PinchZoom\": {\n      \"additionalProperties\": false,\n      \"description\": \"Zoom in and out using pinch gestures.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"pinchZoom\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.PreventDefault\": {\n      \"additionalProperties\": false,\n      \"description\": \"No action.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"preventDefault\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Modifiers.Zoom\": {\n      \"additionalProperties\": false,\n      \"description\": \"Zoom in and out using ⌘+ and ⌘-.\",\n      \"properties\": {\n        \"type\": {\n          \"const\": \"zoom\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"type\"\n      ],\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Smoothed\": {\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"acceleration\": {\n          \"description\": \"The scrolling acceleration.\",\n          \"type\": \"number\"\n        },\n        \"enabled\": {\n          \"default\": true,\n          \"description\": \"Set to `false` to explicitly disable inherited smoothed scrolling for this direction.\",\n          \"type\": \"boolean\"\n        },\n        \"inertia\": {\n          \"description\": \"The scrolling inertia.\",\n          \"type\": \"number\"\n        },\n        \"preset\": {\n          \"$ref\": \"#/definitions/Scheme.Scrolling.Smoothed.Preset\",\n          \"default\": \"natural\",\n          \"description\": \"The preset curve to use.\"\n        },\n        \"response\": {\n          \"description\": \"How quickly the scrolling responds to input.\",\n          \"type\": \"number\"\n        },\n        \"speed\": {\n          \"description\": \"The scrolling speed.\",\n          \"type\": \"number\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"Scheme.Scrolling.Smoothed.Preset\": {\n      \"enum\": [\n        \"custom\",\n        \"linear\",\n        \"easeIn\",\n        \"easeOut\",\n        \"easeInOut\",\n        \"easeOutIn\",\n        \"quadratic\",\n        \"cubic\",\n        \"quartic\",\n        \"easeOutCubic\",\n        \"easeInOutCubic\",\n        \"easeOutQuartic\",\n        \"easeInOutQuartic\",\n        \"quintic\",\n        \"sine\",\n        \"exponential\",\n        \"circular\",\n        \"back\",\n        \"bounce\",\n        \"elastic\",\n        \"spring\",\n        \"natural\",\n        \"smooth\",\n        \"snappy\",\n        \"gentle\"\n      ],\n      \"type\": \"string\"\n    },\n    \"Secondary\": {\n      \"const\": 1,\n      \"description\": \"Secondary button, usually the right button.\",\n      \"type\": \"number\"\n    },\n    \"SingleValueOrArray<Scheme.Buttons.AutoScroll.Mode>\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.Buttons.AutoScroll.Mode\"\n        },\n        {\n          \"items\": {\n            \"$ref\": \"#/definitions/Scheme.Buttons.AutoScroll.Mode\"\n          },\n          \"type\": \"array\"\n        }\n      ]\n    },\n    \"SingleValueOrArray<Scheme.If.Category>\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.If.Category\"\n        },\n        {\n          \"items\": {\n            \"$ref\": \"#/definitions/Scheme.If.Category\"\n          },\n          \"type\": \"array\"\n        }\n      ]\n    },\n    \"SingleValueOrArray<Scheme.If>\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/Scheme.If\"\n        },\n        {\n          \"items\": {\n            \"$ref\": \"#/definitions/Scheme.If\"\n          },\n          \"type\": \"array\"\n        }\n      ]\n    },\n    \"Unset\": {\n      \"const\": \"unset\",\n      \"description\": \"A special value that explicitly restores a setting to the system or device default. Currently supported in pointer settings; may be supported more broadly in the future.\",\n      \"title\": \"Unset\",\n      \"type\": \"string\"\n    }\n  }\n}\n"
  },
  {
    "path": "Documentation/Configuration.md",
    "content": "# Configuration\n\nThe LinearMouse configuration is stored in `~/.config/linearmouse/linearmouse.json`.\n\nIf the configuration file does not exist, LinearMouse will create an empty configuration automatically.\n\n> **Note**  \n> It's preferable to use the GUI to alter settings rather than manually updating configuration\n> unless you want to use advanced features.\n\n> **Note**  \n> JSON5 is not supported yet. Writing comments in configuration will raise a parsing error.\n\n## Get started\n\nHere is a simple example of LinearMouse configuration.\n\n```json\n{\n  \"$schema\": \"https://app.linearmouse.org/schema/0.7.2\",\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"category\": \"mouse\"\n        }\n      },\n      \"scrolling\": {\n        \"reverse\": {\n          \"vertical\": true\n        }\n      }\n    }\n  ]\n}\n```\n\nThis configuration reverses the vertical scrolling direction for any mouse connected to your device.\n\n## JSON Schema\n\nAs you can see, `$schema` defines the JSON schema of the LinearMouse configuration, which enables\nautocompletion in editors like VS Code.\n\nSON schemas are published for each LinearMouse version. Backward compatibility is guaranteed for\nthe same major versions.\n\n## Schemes\n\nA scheme is a collection of settings that are activated in specified circumstances.\n\nFor example, in [get started](#get-started), we defined a scheme. The `if` field instructs\nLinearMouse to activate this scheme only when the active device is a mouse:\n\n```json\n{\n  \"if\": {\n    \"device\": {\n      \"category\": \"mouse\"\n    }\n  }\n}\n```\n\nAnd the `scrolling` field in this scheme defines the scrolling behaviors, with\n`\"reverse\": { \"vertical\": true }` reversing the vertical scrolling direction:\n\n```json\n{\n  \"scrolling\": {\n    \"reverse\": {\n      \"vertical\": true\n    }\n  }\n}\n```\n\n## Smoothed scrolling\n\n`scrolling.smoothed` enables a phase-aware scrolling curve that can be tuned separately for\nvertical and horizontal scrolling. You can choose a preset such as `easeIn`, `easeOut`,\n`easeInOut`, `quadratic`, `cubic`, `easeOutCubic`, `easeInOutCubic`, `quartic`,\n`easeOutQuartic`, `easeInOutQuartic`, `smooth`, or `custom`, then fine-tune `response`,\n`speed`, `acceleration`, and `inertia` as needed.\n\nSet `enabled` to `false` to explicitly disable an inherited smoothed scrolling configuration for a\ndirection.\n\nFor example, to use a smoother scrolling profile for a mouse:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"category\": \"mouse\"\n        }\n      },\n      \"scrolling\": {\n        \"smoothed\": {\n          \"enabled\": true,\n          \"preset\": \"easeInOut\",\n          \"response\": 0.45,\n          \"speed\": 1,\n          \"acceleration\": 1.2,\n          \"inertia\": 0.65\n        }\n      }\n    }\n  ]\n}\n```\n\nIf you want different tuning for each direction, provide `vertical` and `horizontal` values under\n`smoothed`.\n\n## Device matching\n\nVendor ID and product ID can be provided to match a specific device.\n\nYou may find these values in About This Mac → System Report... → Bluetooth / USB.\n\nFor example, to configure pointer speed of my Logitech mouse and Microsoft mouse respectively,\nI would create two schemes and specify the vendor ID and product ID:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x046d\",\n          \"productID\": \"0xc52b\"\n        }\n      },\n      \"pointer\": {\n        \"acceleration\": 0,\n        \"speed\": 0.36\n      }\n    },\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x045e\",\n          \"productID\": \"0x0827\"\n        }\n      },\n      \"pointer\": {\n        \"acceleration\": 0,\n        \"speed\": 0.4\n      }\n    }\n  ]\n}\n```\n\nThen, the pointer speed of my Logitech mouse and Microsoft mouse will be set to 0.36 and 0.4\nrespectively.\n\n### Unsetting values\n\nLinearMouse supports a special \"unset\" value to explicitly restore settings back to their system or\ndevice defaults. This differs from omitting a field, which keeps the previously merged value.\n\nCurrently, \"unset\" is supported for pointer acceleration and speed.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": { \"category\": \"mouse\" }\n      },\n      \"pointer\": { \"acceleration\": \"unset\", \"speed\": \"unset\" }\n    }\n  ]\n}\n```\n\n## App matching\n\nApp bundle ID can be provided to match a specific app.\n\nFor example, to modify the pointer acceleration in Safari for my Logitech mouse:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x046d\",\n          \"productID\": \"0xc52b\"\n        },\n        \"app\": \"com.apple.Safari\"\n      },\n      \"pointer\": {\n        \"acceleration\": 0.5\n      }\n    }\n  ]\n}\n```\n\nOr, to disable reverse scrolling in Safari for all devices:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"app\": \"com.apple.Safari\"\n      },\n      \"scrolling\": {\n        \"reverse\": {\n          \"vertical\": false,\n          \"horizontal\": false\n        }\n      }\n    }\n  ]\n}\n```\n\nBy default, LinearMouse checks the app bundle ID of the frontmost process. However, in some\ncircumstances, a program might not be placed in a specific application bundle. In that case, you\nmay specify the app bundle ID of the parent process or the process group of the frontmost process\nby specify `parentApp` and `groupApp`.\n\nFor example, to match the Minecraft (a Java process) launched by PolyMC:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"parentApp\": \"org.polymc.PolyMC\"\n      }\n    }\n  ]\n}\n```\n\nOr, to match the whole process group:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"groupApp\": \"org.polymc.PolyMC\"\n      }\n    }\n  ]\n}\n```\n\n### Process (binary) matching\n\nSome programs do not have a stable or any bundle identifier. You can match by the frontmost process's executable instead.\n\n- processName: Match by executable name (case-sensitive). Example:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"processName\": \"wezterm\"\n      },\n      \"scrolling\": { \"reverse\": false }\n    }\n  ]\n}\n```\n\n- processPath: Match by absolute executable path (case-sensitive). Example:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"processPath\": \"/Applications/WezTerm.app/Contents/MacOS/WezTerm\"\n      },\n      \"pointer\": { \"acceleration\": 0.4 }\n    }\n  ]\n}\n```\n\nNotes\n- processName/processPath compare exactly; no wildcard or regex.\n- Matching is against the frontmost application process (NSRunningApplication); child processes inside a terminal are not detected as the frontmost process.\n- You can still combine with device and display conditions.\n\n## Display Matching\n\nDisplay name can be provided to match a specific display.\n\nFor example, to modify the pointer acceleration on DELL P2415Q:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x046d\",\n          \"productID\": \"0xc52b\"\n        },\n        \"display\": \"DELL P2415Q\"\n      },\n      \"pointer\": {\n        \"acceleration\": 0.5\n      }\n    }\n  ]\n}\n```\n\n## Schemes merging and multiple `if`s\n\nIf multiple schemes are activated at the same time, they will be merged in the order of their\ndefinitions.\n\nAdditionally, if multiple `if`s are specified, the scheme will be activated as long as any of them\nis satisfied.\n\nFor example, the configuration above can alternatively be written as:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"vendorID\": \"0x046d\",\n            \"productID\": \"0xc52b\"\n          }\n        },\n        {\n          \"device\": {\n            \"vendorID\": \"0x045e\",\n            \"productID\": \"0x0827\"\n          }\n        }\n      ],\n      \"pointer\": {\n        \"acceleration\": 0\n      }\n    },\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x046d\",\n          \"productID\": \"0xc52b\"\n        }\n      },\n      \"pointer\": {\n        \"speed\": 0.36\n      }\n    },\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x045e\",\n          \"productID\": \"0x0827\"\n        }\n      },\n      \"pointer\": {\n        \"speed\": 0.4\n      }\n    }\n  ]\n}\n```\n\nOr, with fewer lines but more difficult to maintain:\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"vendorID\": \"0x046d\",\n            \"productID\": \"0xc52b\"\n          }\n        },\n        {\n          \"device\": {\n            \"vendorID\": \"0x045e\",\n            \"productID\": \"0x0827\"\n          }\n        }\n      ],\n      \"pointer\": {\n        \"acceleration\": 0,\n        \"speed\": 0.36\n      }\n    },\n    {\n      \"if\": {\n        \"device\": {\n          \"vendorID\": \"0x045e\",\n          \"productID\": \"0x0827\"\n        }\n      },\n      \"pointer\": {\n        \"speed\": 0.4\n      }\n    }\n  ]\n}\n```\n\n## Button mappings\n\nButton mappings is a list that allows you to assign actions to buttons or scroll wheels.\nFor example, to open Launchpad when the wheel button is clicked, or to switch spaces when\n<kbd>command + back</kbd> or <kbd>command + forward</kbd> is clicked.\n\n### Basic example\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"category\": \"mouse\"\n          }\n        }\n      ],\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"button\": 2,\n            \"action\": \"launchpad\"\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\nIn this example, the wheel button is bound to open Launchpad.\n\n`\"button\": 2` denotes the auxiliary button, which is usually the wheel button.\n\nThe following table lists all the buttons:\n\n| Button | Description                                                      |\n| ------ | ---------------------------------------------------------------- |\n| 0      | Primary button, usually the left button.                         |\n| 1      | Secondary button, usually the right button.                      |\n| 2      | Auxiliary button, usually the wheel button or the middle button. |\n| 3      | The fourth button, typically the back button.                    |\n| 4      | The fifth button, typically the forward button.                  |\n| 5-31   | Other buttons.                                                   |\n\n`{ \"action\": { \"run\": \"open -a Launchpad\" } }` assigns a shell command `open -a LaunchPad` to\nthe button. When the button is clicked, the shell command will be executed.\n\n### Modifier keys\n\nIn this example, <kbd>command + forward</kbd> is bound to open Mission Control.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"category\": \"mouse\"\n          }\n        }\n      ],\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"button\": 4,\n            \"command\": true,\n            \"action\": \"missionControl\"\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\n`\"command\": true` denotes that <kbd>command</kbd> should be pressed.\n\nYou can specify `shift`, `option` and `control` as well.\n\n### Switch spaces (desktops) with the <kbd>command + back</kbd> and <kbd>command + forward</kbd>\n\n`missionControl.spaceLeft` and `missionControl.spaceRight` can be used to move left and right a space.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"category\": \"mouse\"\n          }\n        }\n      ],\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"button\": 3,\n            \"command\": true,\n            \"action\": \"missionControl.spaceLeft\"\n          },\n          {\n            \"button\": 4,\n            \"command\": true,\n            \"action\": \"missionControl.spaceRight\"\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\n> **Note**  \n> You will have to grant an additional permission to allow LinearMouse to simulate keys.\n\n### Key repeat\n\nWith `repeat: true`, actions will be repeated until the button is up.\n\nIn this example, <kbd>option + back</kbd> and <kbd>option + forward</kbd> is bound to volume down\nand volume up.\n\nIf you hold <kbd>option + back</kbd>, the volume will continue to decrease.\n\n> **Note**  \n> If you disabled key repeat in System Settings, `repeat: true` will not work.\n> If you change key repeat rate or delay until repeat in System Settings, you have to restart\n> LinearMouse to take effect.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"category\": \"mouse\"\n          }\n        }\n      ],\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"button\": 4,\n            \"repeat\": true,\n            \"option\": true,\n            \"action\": \"media.volumeUp\"\n          },\n          {\n            \"button\": 3,\n            \"repeat\": true,\n            \"option\": true,\n            \"action\": \"media.volumeDown\"\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\n### Hold keyboard shortcuts while pressed\n\nWith `hold: true`, keyboard shortcut actions stay pressed for as long as the mouse button is held.\n\nThis is different from `repeat: true`:\n\n- `repeat: true` keeps sending the shortcut over and over.\n- `hold: true` sends key down when the mouse button is pressed, then key up when it is released.\n\nThis is useful for apps that expect a real held key, such as timeline scrubbing or temporary tools.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"category\": \"mouse\"\n        }\n      },\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"button\": 3,\n            \"hold\": true,\n            \"action\": {\n              \"keyPress\": [\"c\"]\n            }\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\n### Volume up and down with <kbd>option + scrollUp</kbd> and <kbd>option + scrollDown</kbd>\n\n`scroll` can be specified instead of `button` to map scroll events to specific actions.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"category\": \"mouse\"\n          }\n        }\n      ],\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"scroll\": \"up\",\n            \"option\": true,\n            \"action\": \"media.volumeUp\"\n          },\n          {\n            \"scroll\": \"down\",\n            \"option\": true,\n            \"action\": \"media.volumeDown\"\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\n### Swap back and forward buttons\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": [\n        {\n          \"device\": {\n            \"category\": \"mouse\"\n          }\n        }\n      ],\n      \"buttons\": {\n        \"mappings\": [\n          {\n            \"button\": 3,\n            \"action\": \"mouse.button.forward\"\n          },\n          {\n            \"button\": 4,\n            \"action\": \"mouse.button.back\"\n          }\n        ]\n      }\n    }\n  ]\n}\n```\n\n### Action sheet\n\n#### Simple actions\n\nA simple action is an action without any parameters.\n\n```json\n{\n  \"action\": \"<action>\"\n}\n```\n\n`<action>` could be one of:\n\n| Action                      | Description                           |\n| --------------------------- | ------------------------------------- |\n| `auto`                      | Do not modify the button behavior.    |\n| `none`                      | Prevent the button events.            |\n| `missionControl`            | Mission Control.                      |\n| `missionControl.spaceLeft`  | Mission Control: Move left a space.   |\n| `missionControl.spaceRight` | Mission Control: Move right a space.  |\n| `appExpose`                 | App Exposé.                           |\n| `launchpad`                 | Launchpad.                            |\n| `showDesktop`               | Show desktop.                         |\n| `showDesktop`               | Show desktop.                         |\n| `lookUpAndDataDetectors`    | Look up & data detectors.             |\n| `smartZoom`                 | Smart zoom.                           |\n| `display.brightnessUp`      | Display: Brightness up.               |\n| `display.brightnessDown`    | Display: Brightness down.             |\n| `media.volumeUp`            | Media: Volume up.                     |\n| `media.volumeDown`          | Media: Volume down.                   |\n| `media.mute`                | Media: Toggle mute.                   |\n| `media.playPause`           | Media: Play / pause.                  |\n| `media.next`                | Media: Next.                          |\n| `media.previous`            | Media: Previous.                      |\n| `media.fastForward`         | Media: Fast forward.                  |\n| `media.rewind`              | Media: Rewind.                        |\n| `keyboard.brightnessUp`     | Keyboard: Brightness up.              |\n| `keyboard.brightnessDown`   | Keyboard: Brightness down.            |\n| `mouse.wheel.scrollUp`      | Mouse: Wheel: Scroll up.              |\n| `mouse.wheel.scrollDown`    | Mouse: Wheel: Scroll down.            |\n| `mouse.wheel.scrollLeft`    | Mouse: Wheel: Scroll left.            |\n| `mouse.wheel.scrollRight`   | Mouse: Wheel: Scroll right.           |\n| `mouse.button.left`         | Mouse: Button: Act as left button.    |\n| `mouse.button.middle`       | Mouse: Button: Act as middle button.  |\n| `mouse.button.right`        | Mouse: Button: Act as right button.   |\n| `mouse.button.back`         | Mouse: Button: Act as back button.    |\n| `mouse.button.forward`      | Mouse: Button: Act as forward button. |\n\n#### Run shell commands\n\n```json\n{\n  \"action\": {\n    \"run\": \"<command>\"\n  }\n}\n```\n\nThe `<command>` will be executed with bash.\n\n#### Scroll a certain distance\n\n##### Scroll up 2 lines\n\n```json\n{\n  \"action\": {\n    \"mouse.wheel.scrollUp\": 2\n  }\n}\n```\n\n##### Scroll left 32 pixels\n\n```json\n{\n  \"action\": {\n    \"mouse.wheel.scrollLeft\": \"32px\"\n  }\n}\n```\n\n#### Press keyboard shortcuts\n\n```json\n{\n  \"action\": {\n    \"keyPress\": [\"shift\", \"command\", \"4\"]\n  }\n}\n```\n\nTo see the full list of keys, please refer to [Configuration.d.ts#L652](Configuration.d.ts#L652).\n\n#### Numpad keys support\n\nLinearMouse supports all numpad keys for keyboard shortcuts:\n\n- Number keys: `numpad0`, `numpad1`, `numpad2`, `numpad3`, `numpad4`, `numpad5`, `numpad6`, `numpad7`, `numpad8`, `numpad9`\n- Operator keys: `numpadPlus`, `numpadMinus`, `numpadMultiply`, `numpadDivide`, `numpadEquals`\n- Function keys: `numpadEnter`, `numpadDecimal`, `numpadClear`\n\nExample usage:\n```json\n{\n  \"action\": {\n    \"keyPress\": [\"numpad5\"]\n  }\n}\n```\n\n## Pointer settings\n\n### Redirects to scroll\n\nThe `redirectsToScroll` property allows you to redirect pointer movements to scroll events. This is useful for scenarios where you want mouse movements to control scrolling instead of cursor positioning.\n\n```json\n{\n  \"schemes\": [\n    {\n      \"if\": {\n        \"device\": {\n          \"category\": \"mouse\"\n        }\n      },\n      \"pointer\": {\n        \"redirectsToScroll\": true\n      }\n    }\n  ]\n}\n```\n\nWhen `redirectsToScroll` is set to `true`, horizontal mouse movements will generate horizontal scroll events, and vertical mouse movements will generate vertical scroll events.\n"
  },
  {
    "path": "Documentation/translate-xcstrings.md",
    "content": "# XCStrings LLM Translation Script\n\n`Scripts/translate-xcstrings.mjs` uses Xcode's native localization export/import flow, then fills unfinished xcstrings entries with an LLM through OpenRouter.\n\nWhat it does:\n\n- exports `.xcloc` / `.xliff` bundles with `xcodebuild -exportLocalizations`\n- inspects only `.xcstrings` translation units inside the exported XLIFF\n- skips units whose target is already `translated`\n- sends only unfinished units to the model\n- imports the translated XLIFF back with `xcodebuild -importLocalizations -mergeImport`\n\n## Install\n\n```bash\nnpm install\n```\n\n## Required environment variables\n\n```bash\nexport OPENROUTER_API_KEY=\"your-api-key\"\n```\n\nOptional:\n\n```bash\nexport OPENROUTER_MODEL=\"openai/gpt-4.1-mini\"\nexport OPENROUTER_SITE_URL=\"https://github.com/linearmouse/linearmouse\"\nexport OPENROUTER_APP_NAME=\"LinearMouse xcstrings translator\"\n```\n\n## Usage\n\nDry run first:\n\n```bash\nnpm run translate:xcstrings -- --dry-run\n```\n\nTranslate everything unfinished:\n\n```bash\nnpm run translate:xcstrings\n```\n\nTranslate only selected languages:\n\n```bash\nnpm run translate:xcstrings -- --languages ja,zh-Hans,zh-Hant\n```\n\nUse a different model or smaller batches:\n\n```bash\nnpm run translate:xcstrings -- --model openai/gpt-4.1 --batch-size 5\n```\n\nLimit a test run to a few translation units:\n\n```bash\nnpm run translate:xcstrings -- --max-units 20\n```\n\nKeep the exported localization bundle for inspection:\n\n```bash\nnpm run translate:xcstrings -- --languages ja --keep-export\n```\n\n## Notes\n\n- The script uses the OpenAI SDK against OpenRouter's OpenAI-compatible endpoint.\n- Extraction and import are handled by Xcode, not by a custom xcstrings parser.\n- The script only edits XLIFF units whose `original` file ends with `.xcstrings`; other exported resources are left untouched.\n- Xcode's exported XLIFF already expands plural and variation entries into individual `trans-unit` items, so the model works on those units directly.\n- Review the diff after each run because model translations can still need terminology cleanup.\n"
  },
  {
    "path": "ExportOptions.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>destination</key>\n\t<string>export</string>\n\t<key>method</key>\n\t<string>developer-id</string>\n\t<key>signingCertificate</key>\n\t<string>Developer ID Application</string>\n\t<key>signingStyle</key>\n\t<string>manual</string>\n\t<key>teamID</key>\n\t<string>C5686NKYJ7</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021-2024 LinearMouse\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "LinearMouse/AccessibilityPermission.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\nimport SwiftUI\n\nenum AccessibilityPermission {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"AccessibilityPermission\")\n\n    static var enabled: Bool {\n        AXIsProcessTrustedWithOptions([\n            kAXTrustedCheckOptionPrompt.takeUnretainedValue(): false\n        ] as CFDictionary)\n    }\n\n    static func prompt() {\n        AXIsProcessTrustedWithOptions([\n            kAXTrustedCheckOptionPrompt.takeUnretainedValue(): true\n        ] as CFDictionary)\n    }\n\n    static func pollingUntilEnabled(completion: @escaping () -> Void) {\n        guard enabled else {\n            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n                os_log(\"Polling accessibility permission\", log: log, type: .info)\n                pollingUntilEnabled(completion: completion)\n            }\n            return\n        }\n        completion()\n    }\n}\n\nenum AccessibilityPermissionError: Error {\n    case resetError\n}\n"
  },
  {
    "path": "LinearMouse/AppDelegate.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppMover\nimport Combine\nimport LaunchAtLogin\nimport os.log\nimport SwiftUI\n\n@main\nclass AppDelegate: NSObject, NSApplicationDelegate {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"AppDelegate\")\n\n    private let autoUpdateManager = AutoUpdateManager.shared\n    private let statusItem = StatusItem.shared\n    private var subscriptions = Set<AnyCancellable>()\n\n    func applicationDidFinishLaunching(_: Notification) {\n        guard ProcessEnvironment.isRunningApp else {\n            return\n        }\n\n        #if !DEBUG\n            if AppMover.moveIfNecessary() {\n                return\n            }\n        #endif\n\n        guard AccessibilityPermission.enabled else {\n            AccessibilityPermissionWindow.shared.bringToFront()\n            return\n        }\n\n        setup()\n\n        if CommandLine.arguments.contains(\"--show\") {\n            SettingsWindowController.shared.bringToFront()\n        }\n    }\n\n    func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows flag: Bool) -> Bool {\n        guard ProcessEnvironment.isRunningApp else {\n            return true\n        }\n\n        if flag {\n            return true\n        }\n\n        SettingsWindowController.shared.bringToFront()\n\n        return false\n    }\n\n    func applicationWillTerminate(_: Notification) {\n        guard ProcessEnvironment.isRunningApp else {\n            return\n        }\n\n        stop()\n    }\n}\n\nextension AppDelegate {\n    func setup() {\n        setupConfiguration()\n        setupNotifications()\n        KeyboardSettingsSnapshot.shared.refresh()\n        start()\n    }\n\n    func setupConfiguration() {\n        ConfigurationState.shared.load()\n        // Start watching the configuration file for hot reload\n        ConfigurationState.shared.startHotReload()\n    }\n\n    func setupNotifications() {\n        // Prepare user notifications for error popups\n        Notifier.shared.setup()\n        NSWorkspace.shared.notificationCenter.addObserver(\n            forName: NSWorkspace.sessionDidResignActiveNotification,\n            object: nil,\n            queue: .main\n        ) { [weak self] _ in\n            os_log(\"Session inactive\", log: Self.log, type: .info)\n            self?.stop()\n        }\n\n        NSWorkspace.shared.notificationCenter.addObserver(\n            forName: NSWorkspace.sessionDidBecomeActiveNotification,\n            object: nil,\n            queue: .main\n        ) { [weak self] _ in\n            os_log(\"Session active\", log: Self.log, type: .info)\n            KeyboardSettingsSnapshot.shared.refresh()\n            self?.start()\n        }\n    }\n\n    func start() {\n        DeviceManager.shared.start()\n        BatteryDeviceMonitor.shared.start()\n        GlobalEventTap.shared.start()\n    }\n\n    func stop() {\n        BatteryDeviceMonitor.shared.stop()\n        DeviceManager.shared.stop()\n        GlobalEventTap.shared.stop()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xF6\",\n          \"green\" : \"0x82\",\n          \"red\" : \"0x3A\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/AccessibilityIcon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"UniversalAccessPref@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"filename\" : \"Icon-32.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"filename\" : \"Icon-33.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"Icon-64.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"Icon-128.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"Icon-256.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"Icon-257.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"Icon-513.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"Icon-512.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"512x512\"\n    },\n    {\n      \"filename\" : \"Icon-1024.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"512x512\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/AppIconDev.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"Icon-512.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"512x512\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"512x512\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/MenuIcon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"MenuIcon.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"MenuIcon@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"filename\" : \"MenuIcon@3x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Minus.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"minus.svg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Plus.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"plus.svg\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Sidebar/Buttons.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"button.programmable@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Sidebar/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Sidebar/General.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"gearshape.fill@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Sidebar/Modifier Keys.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"command@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Sidebar/Pointer.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"cursorarrow@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/Assets.xcassets/Sidebar/Scrolling.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"filename\" : \"arrow.up.and.down@2x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "LinearMouse/AutoUpdateManager.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\nimport Foundation\nimport Sparkle\nimport Version\n\nclass AutoUpdateManager: NSObject {\n    static let shared = AutoUpdateManager()\n\n    private var _controller: SPUStandardUpdaterController!\n    var controller: SPUStandardUpdaterController {\n        _controller\n    }\n\n    override init() {\n        super.init()\n        _controller = SPUStandardUpdaterController(\n            startingUpdater: true,\n            updaterDelegate: self,\n            userDriverDelegate: nil\n        )\n    }\n}\n\nextension AutoUpdateManager: SPUUpdaterDelegate {\n    func allowedChannels(for _: SPUUpdater) -> Set<String> {\n        Defaults[.betaChannelOn] ? [\"beta\"] : []\n    }\n\n    func versionComparator(for _: SPUUpdater) -> SUVersionComparison? {\n        SemanticVersioningComparator()\n    }\n}\n\nclass SemanticVersioningComparator: SUVersionComparison {\n    func compareVersion(_ versionA: String, toVersion versionB: String) -> ComparisonResult {\n        guard let a = try? Version(versionA) else {\n            return .orderedAscending\n        }\n        guard let b = try? Version(versionB) else {\n            return .orderedDescending\n        }\n        if a < b {\n            return .orderedAscending\n        }\n        if a > b {\n            return .orderedDescending\n        }\n        return .orderedSame\n    }\n}\n"
  },
  {
    "path": "LinearMouse/DefaultsKeys.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\n\nenum MenuBarBatteryDisplayMode: String, Codable, Defaults.Serializable {\n    case off\n    case below5\n    case below10\n    case below15\n    case below20\n    case always\n\n    var threshold: Int? {\n        switch self {\n        case .off:\n            return nil\n        case .below5:\n            return 5\n        case .below10:\n            return 10\n        case .below15:\n            return 15\n        case .below20:\n            return 20\n        case .always:\n            return 100\n        }\n    }\n}\n\nextension Defaults.Keys {\n    static let showInMenuBar = Key<Bool>(\"showInMenuBar\", default: true)\n    static let menuBarBatteryDisplayMode = Key<MenuBarBatteryDisplayMode>(\"menuBarBatteryDisplayMode\", default: .off)\n\n    static let showInDock = Key<Bool>(\"showInDock\", default: true)\n\n    static let betaChannelOn = Key(\"betaChannelOn\", default: false)\n\n    static let bypassEventsFromOtherApplications = Key(\"bypassEventsFromOtherApplications\", default: false)\n\n    static let verbosedLoggingOn = Key(\"verbosedLoggingOn\", default: false)\n}\n"
  },
  {
    "path": "LinearMouse/Device/Device.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\nimport Foundation\nimport ObservationToken\nimport os.log\nimport PointerKit\n\nclass Device {\n    private static let log = OSLog(\n        subsystem: Bundle.main.bundleIdentifier!, category: \"Device\"\n    )\n\n    static let fallbackPointerAcceleration = 0.6875\n    static let fallbackPointerResolution = 400.0\n    static let fallbackPointerSpeed = pointerSpeed(\n        fromPointerResolution: fallbackPointerResolution\n    )\n\n    private static var nextID: Int32 = 0\n\n    private(set) lazy var id: Int32 = OSAtomicIncrement32(&Self.nextID)\n\n    var name: String\n    var productName: String?\n    var vendorID: Int?\n    var productID: Int?\n    var serialNumber: String?\n    var buttonCount: Int?\n    var batteryLevel: Int?\n    private let categoryValue: Category\n\n    private weak var manager: DeviceManager?\n    private var inputReportHandlers: [InputReportHandler] = []\n    private var logitechReprogrammableControlsMonitor: LogitechReprogrammableControlsMonitor?\n    private let device: PointerDevice\n\n    var pointerDevice: PointerDevice {\n        device\n    }\n\n    private var removed = false\n\n    private var verbosedLoggingOn = Defaults[.verbosedLoggingOn]\n\n    private let initialPointerResolution: Double\n\n    private var inputObservationToken: ObservationToken?\n    private var reportObservationToken: ObservationToken?\n\n    private var lastButtonStates: UInt8 = 0\n\n    var category: Category {\n        categoryValue\n    }\n\n    init(_ manager: DeviceManager, _ device: PointerDevice) {\n        self.manager = manager\n        self.device = device\n\n        vendorID = device.vendorID\n        productID = device.productID\n        serialNumber = device.serialNumber\n        buttonCount = device.buttonCount\n\n        let rawProductName = device.product\n        let rawName = rawProductName ?? device.name\n        name = rawName\n        productName = rawProductName\n        batteryLevel = nil\n        categoryValue = Self.detectCategory(for: device)\n\n        initialPointerResolution =\n            device.pointerResolution ?? Self.fallbackPointerResolution\n\n        // TODO: More elegant way?\n        inputObservationToken = device.observeInput { [weak self] in\n            self?.inputValueCallback($0, $1)\n        }\n\n        // Some bluetooth devices, such as Mi Dual Mode Wireless Mouse Silent Edition, report only\n        // 3 buttons in the HID report descriptor. As a result, macOS does not recognize side button\n        // clicks from these devices.\n        //\n        // To work around this issue, we subscribe to the input reports and monitor the side button\n        // states. When the side buttons are clicked, we simulate those events.\n        if let vendorID, let productID {\n            let handlers = InputReportHandlerRegistry.handlers(for: vendorID, productID: productID)\n            let needsObservation = handlers.contains { $0.alwaysNeedsReportObservation() } || buttonCount == 3\n            if needsObservation, !handlers.isEmpty {\n                inputReportHandlers = handlers\n                reportObservationToken = device.observeReport { [weak self] in\n                    self?.inputReportCallback($0, $1)\n                }\n            }\n        }\n\n        if LogitechReprogrammableControlsMonitor.supports(device: self) {\n            let monitor = LogitechReprogrammableControlsMonitor(device: self)\n            logitechReprogrammableControlsMonitor = monitor\n            monitor.start()\n        }\n\n        os_log(\n            \"Device initialized: %{public}@: HIDPointerResolution=%{public}f, HIDPointerAccelerationType=%{public}@, battery=%{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: device),\n            initialPointerResolution,\n            device.pointerAccelerationType ?? \"(unknown)\",\n            batteryLevel.map(formattedPercent) ?? \"(unknown)\"\n        )\n\n        Defaults.observe(.verbosedLoggingOn) { [weak self] change in\n            guard let self else {\n                return\n            }\n\n            verbosedLoggingOn = change.newValue\n        }\n        .tieToLifetime(of: self)\n    }\n\n    func markRemoved() {\n        removed = true\n\n        inputObservationToken = nil\n        reportObservationToken = nil\n        logitechReprogrammableControlsMonitor?.stop()\n        logitechReprogrammableControlsMonitor = nil\n    }\n\n    func markActive(reason: String) {\n        manager?.markDeviceActive(self, reason: reason)\n    }\n\n    var hasLogitechControlsMonitor: Bool {\n        logitechReprogrammableControlsMonitor != nil\n    }\n\n    func requestLogitechControlsForcedReconfiguration() {\n        logitechReprogrammableControlsMonitor?.requestForcedReconfiguration()\n    }\n}\n\nextension Device {\n    enum Category {\n        case mouse, trackpad\n    }\n\n    private static let appleVendorIDs = Set([0x004C, 0x05AC])\n    private static let appleMagicMouseProductIDs = Set([0x0269, 0x030D])\n    private static let appleMagicTrackpadProductIDs = Set([0x0265, 0x030E])\n    private static let appleBuiltInTrackpadProductIDs = Set([0x0273, 0x0276, 0x0278, 0x0340])\n\n    private static func detectCategory(for device: PointerDevice) -> Category {\n        if let vendorID = device.vendorID,\n           let productID = device.productID,\n           isAppleMagicMouse(vendorID: vendorID, productID: productID) {\n            return .mouse\n        }\n\n        if device.confirmsTo(kHIDPage_Digitizer, kHIDUsage_Dig_TouchPad) {\n            return .trackpad\n        }\n\n        return .mouse\n    }\n\n    private static func isAppleMagicMouse(vendorID: Int, productID: Int) -> Bool {\n        appleVendorIDs.contains(vendorID)\n            && appleMagicMouseProductIDs.contains(productID)\n    }\n\n    private static func isAppleMagicTrackpad(vendorID: Int, productID: Int) -> Bool {\n        appleVendorIDs.contains(vendorID)\n            && appleMagicTrackpadProductIDs.contains(productID)\n    }\n\n    private static func isAppleBuiltInTrackpad(vendorID: Int, productID: Int) -> Bool {\n        vendorID == 0x05AC\n            && appleBuiltInTrackpadProductIDs.contains(productID)\n    }\n\n    var showsPointerSpeedLimitationNotice: Bool {\n        guard let vendorID, let productID else {\n            return false\n        }\n\n        return Self.isAppleMagicMouse(vendorID: vendorID, productID: productID)\n            || Self.isAppleMagicTrackpad(vendorID: vendorID, productID: productID)\n            || Self.isAppleBuiltInTrackpad(vendorID: vendorID, productID: productID)\n    }\n\n    /**\n     This feature was introduced in macOS Sonoma. In the earlier versions of\n     macOS, this value would be nil.\n     */\n    var disablePointerAcceleration: Bool? {\n        get {\n            device.useLinearScalingMouseAcceleration.map { $0 != 0 }\n        }\n        set {\n            guard device.useLinearScalingMouseAcceleration != nil, let newValue else {\n                return\n            }\n            device.useLinearScalingMouseAcceleration = newValue ? 1 : 0\n        }\n    }\n\n    var pointerAcceleration: Double {\n        get {\n            device.pointerAcceleration ?? Self.fallbackPointerAcceleration\n        }\n        set {\n            os_log(\n                \"Update pointer acceleration for device: %{public}@: %{public}f\",\n                log: Self.log,\n                type: .info,\n                String(describing: self),\n                newValue\n            )\n            device.pointerAcceleration = newValue\n        }\n    }\n\n    private static let pointerSpeedRange = 1.0 / 1200 ... 1.0 / 40\n\n    static func pointerSpeed(fromPointerResolution pointerResolution: Double)\n        -> Double {\n        (1 / pointerResolution).normalized(from: pointerSpeedRange)\n    }\n\n    static func pointerResolution(fromPointerSpeed pointerSpeed: Double)\n        -> Double {\n        1 / (pointerSpeed.normalized(to: pointerSpeedRange))\n    }\n\n    var pointerSpeed: Double {\n        get {\n            device.pointerResolution.map {\n                Self.pointerSpeed(fromPointerResolution: $0)\n            }\n                ?? Self\n                .fallbackPointerSpeed\n        }\n        set {\n            os_log(\n                \"Update pointer speed for device: %{public}@: %{public}f\",\n                log: Self.log,\n                type: .info,\n                String(describing: self),\n                newValue\n            )\n            device.pointerResolution = Self.pointerResolution(fromPointerSpeed: newValue)\n        }\n    }\n\n    func restorePointerAcceleration() {\n        let systemPointerAcceleration = (DeviceManager.shared\n            .getSystemProperty(forKey: device.pointerAccelerationType ?? kIOHIDMouseAccelerationTypeKey) as IOFixed?\n        )\n        .map { Double($0) / 65_536 } ?? Self.fallbackPointerAcceleration\n\n        os_log(\n            \"Restore pointer acceleration for device: %{public}@: %{public}f\",\n            log: Self.log,\n            type: .info,\n            String(describing: device),\n            systemPointerAcceleration\n        )\n\n        pointerAcceleration = systemPointerAcceleration\n    }\n\n    func restorePointerSpeed() {\n        os_log(\n            \"Restore pointer speed for device: %{public}@: %{public}f\",\n            log: Self.log,\n            type: .info,\n            String(describing: device),\n            Self.pointerSpeed(fromPointerResolution: initialPointerResolution)\n        )\n\n        device.pointerResolution = initialPointerResolution\n    }\n\n    func restorePointerAccelerationAndPointerSpeed() {\n        restorePointerSpeed()\n        restorePointerAcceleration()\n    }\n\n    private func inputValueCallback(\n        _ device: PointerDevice, _ value: IOHIDValue\n    ) {\n        if verbosedLoggingOn {\n            os_log(\n                \"Received input value from: %{public}@: %{public}@\",\n                log: Self.log,\n                type: .info,\n                String(describing: device),\n                String(describing: value)\n            )\n        }\n\n        guard let manager else {\n            os_log(\"manager is nil\", log: Self.log, type: .error)\n            return\n        }\n\n        guard manager.lastActiveDeviceId != id else {\n            return\n        }\n\n        let element = value.element\n\n        let usagePage = element.usagePage\n        let usage = element.usage\n\n        switch Int(usagePage) {\n        case kHIDPage_GenericDesktop:\n            switch Int(usage) {\n            case kHIDUsage_GD_X, kHIDUsage_GD_Y, kHIDUsage_GD_Z:\n                guard IOHIDValueGetIntegerValue(value) != 0 else {\n                    return\n                }\n            default:\n                return\n            }\n        case kHIDPage_Button:\n            break\n        default:\n            return\n        }\n\n        manager.markDeviceActive(\n            self,\n            reason: \"Received input value: usagePage=0x\\(String(format: \"%02X\", usagePage)), usage=0x\\(String(format: \"%02X\", usage))\"\n        )\n    }\n\n    private func inputReportCallback(_ device: PointerDevice, _ report: Data) {\n        if verbosedLoggingOn {\n            let reportHex = report.map { String(format: \"%02X\", $0) }.joined(separator: \" \")\n            os_log(\n                \"Received input report from: %{public}@: %{public}@\",\n                log: Self.log,\n                type: .info,\n                String(describing: device),\n                String(describing: reportHex)\n            )\n        }\n\n        let context = InputReportContext(report: report, lastButtonStates: lastButtonStates)\n        let chain = inputReportHandlers.reversed().reduce({ (_: InputReportContext) in }) { next, handler in\n            { context in handler.handleReport(context, next: next) }\n        }\n        chain(context)\n        lastButtonStates = context.lastButtonStates\n    }\n}\n\nextension Device: Hashable {\n    static func == (lhs: Device, rhs: Device) -> Bool {\n        lhs === rhs\n    }\n\n    func hash(into hasher: inout Hasher) {\n        hasher.combine(ObjectIdentifier(self))\n    }\n}\n\nextension Device: CustomStringConvertible {\n    var description: String {\n        let vendorIDString = vendorID.map { String(format: \"0x%04X\", $0) } ?? \"(nil)\"\n        let productIDString = productID.map { String(format: \"0x%04X\", $0) } ?? \"(nil)\"\n        return String(format: \"%@ (VID=%@, PID=%@)\", name, vendorIDString, productIDString)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/DeviceManager.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Combine\nimport Foundation\nimport os.log\nimport PointerKit\n\nclass DeviceManager: ObservableObject {\n    static let shared = DeviceManager()\n\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"DeviceManager\")\n\n    private let manager = PointerDeviceManager()\n    private let receiverMonitor = ReceiverMonitor()\n\n    private var pointerDeviceToDevice = [PointerDevice: Device]()\n    @Published private(set) var receiverPairedDeviceIdentities = [Int: [ReceiverLogicalDeviceIdentity]]()\n    @Published var devices: [Device] = []\n\n    var lastActiveDeviceId: Int32?\n    @Published var lastActiveDeviceRef: WeakRef<Device>?\n\n    init() {\n        manager.observeDeviceAdded { [weak self] in\n            self?.deviceAdded($0, $1)\n        }\n        .tieToLifetime(of: self)\n\n        manager.observeDeviceRemoved { [weak self] in\n            self?.deviceRemoved($0, $1)\n        }\n        .tieToLifetime(of: self)\n\n        manager.observeEventReceived { [weak self] in\n            self?.eventReceived($0, $1, $2)\n        }\n        .tieToLifetime(of: self)\n\n        receiverMonitor.onPointingDevicesChanged = { [weak self] locationID, identities in\n            self?.receiverPointingDevicesChanged(locationID: locationID, identities: identities)\n        }\n\n        for property in [\n            kIOHIDMouseAccelerationType,\n            kIOHIDTrackpadAccelerationType,\n            kIOHIDPointerResolutionKey,\n            \"HIDUseLinearScalingMouseAcceleration\"\n        ] {\n            manager.observePropertyChanged(property: property) { [self] _ in\n                os_log(\"Property %{public}@ changed\", log: Self.log, type: .info, property)\n                updatePointerSpeed()\n            }.tieToLifetime(of: self)\n        }\n    }\n\n    deinit {\n        stop()\n    }\n\n    private enum State {\n        case stopped, running\n    }\n\n    private var state: State = .stopped\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    private var activateApplicationObserver: Any?\n\n    func stop() {\n        guard state == .running else {\n            return\n        }\n        state = .stopped\n\n        restorePointerSpeedToInitialValue()\n        manager.stopObservation()\n        subscriptions.removeAll()\n\n        if let activateApplicationObserver {\n            NSWorkspace.shared.notificationCenter.removeObserver(activateApplicationObserver)\n        }\n    }\n\n    func start() {\n        guard state == .stopped else {\n            return\n        }\n        state = .running\n\n        manager.startObservation()\n\n        ConfigurationState.shared\n            .$configuration\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .sink { [weak self] _ in\n                guard let self else {\n                    return\n                }\n                DispatchQueue.main.async {\n                    self.updatePointerSpeed()\n                }\n            }\n            .store(in: &subscriptions)\n\n        ScreenManager.shared\n            .$currentScreenName\n            .sink { [weak self] _ in\n                guard let self else {\n                    return\n                }\n                DispatchQueue.main.async {\n                    self.updatePointerSpeed()\n                }\n            }\n            .store(in: &subscriptions)\n\n        activateApplicationObserver = NSWorkspace.shared.notificationCenter.addObserver(\n            forName: NSWorkspace.didActivateApplicationNotification,\n            object: nil,\n            queue: .main\n        ) { [weak self] notification in\n            let application = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication\n            os_log(\n                \"Frontmost app changed: %{public}@\",\n                log: Self.log,\n                type: .info,\n                application?.bundleIdentifier ?? \"(nil)\"\n            )\n            self?.updatePointerSpeed()\n        }\n    }\n\n    private func deviceAdded(_: PointerDeviceManager, _ pointerDevice: PointerDevice) {\n        let device = Device(self, pointerDevice)\n\n        objectWillChange.send()\n\n        pointerDeviceToDevice[pointerDevice] = device\n        refreshVisibleDevices()\n\n        os_log(\n            \"Device added: %{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: device)\n        )\n\n        updatePointerSpeed(for: device)\n\n        if shouldMonitorReceiver(device) {\n            receiverMonitor.startMonitoring(device: device)\n        }\n    }\n\n    private func deviceRemoved(_: PointerDeviceManager, _ pointerDevice: PointerDevice) {\n        guard let device = pointerDeviceToDevice[pointerDevice] else {\n            return\n        }\n        device.markRemoved()\n\n        objectWillChange.send()\n\n        if lastActiveDeviceId == device.id {\n            lastActiveDeviceId = nil\n            lastActiveDeviceRef = nil\n        }\n\n        if let locationID = pointerDevice.locationID {\n            let hasRemainingReceiverAtLocation = pointerDeviceToDevice\n                .filter { $0.key != pointerDevice }\n                .contains { _, existingDevice in\n                    existingDevice.pointerDevice.locationID == locationID && shouldMonitorReceiver(existingDevice)\n                }\n\n            if hasRemainingReceiverAtLocation {\n                os_log(\n                    \"Keep receiver monitor running because another receiver device shares locationID=%{public}d\",\n                    log: Self.log,\n                    type: .info,\n                    locationID\n                )\n            } else {\n                receiverMonitor.stopMonitoring(device: device)\n                receiverPairedDeviceIdentities.removeValue(forKey: locationID)\n            }\n        }\n\n        pointerDeviceToDevice.removeValue(forKey: pointerDevice)\n        refreshVisibleDevices()\n\n        os_log(\n            \"Device removed: %{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: device)\n        )\n    }\n\n    /// Observes events from `DeviceManager`.\n    ///\n    /// It seems that extenal Trackpads do not trigger to `IOHIDDevice`'s inputValueCallback.\n    /// That's why we need to observe events from `DeviceManager` too.\n    private func eventReceived(_: PointerDeviceManager, _ pointerDevice: PointerDevice, _ event: IOHIDEvent) {\n        guard let physicalDevice = pointerDeviceToDevice[pointerDevice] else {\n            return\n        }\n\n        guard IOHIDEventGetType(event) == kIOHIDEventTypeScroll else {\n            return\n        }\n\n        let scrollX = IOHIDEventGetFloatValue(event, kIOHIDEventFieldScrollX)\n        let scrollY = IOHIDEventGetFloatValue(event, kIOHIDEventFieldScrollY)\n        guard scrollX != 0 || scrollY != 0 else {\n            return\n        }\n\n        markDeviceActive(physicalDevice, reason: \"Received event from DeviceManager\")\n    }\n\n    func deviceFromCGEvent(_ cgEvent: CGEvent) -> Device? {\n        // Issue: https://github.com/linearmouse/linearmouse/issues/677#issuecomment-1938208542\n        guard ![.flagsChanged, .keyDown, .keyUp].contains(cgEvent.type) else {\n            return lastActiveDeviceRef?.value\n        }\n\n        guard let ioHIDEvent = CGEventCopyIOHIDEvent(cgEvent) else {\n            return lastActiveDeviceRef?.value\n        }\n\n        guard let pointerDevice = manager.pointerDeviceFromIOHIDEvent(ioHIDEvent) else {\n            return lastActiveDeviceRef?.value\n        }\n\n        guard let physicalDevice = pointerDeviceToDevice[pointerDevice] else {\n            return lastActiveDeviceRef?.value\n        }\n\n        return physicalDevice\n    }\n\n    func updatePointerSpeed() {\n        for device in devices {\n            updatePointerSpeed(for: device)\n        }\n    }\n\n    func updatePointerSpeed(for device: Device) {\n        let scheme = ConfigurationState.shared.configuration.matchScheme(\n            withDevice: device,\n            withPid: NSWorkspace.shared.frontmostApplication?.processIdentifier,\n            withDisplay: ScreenManager.shared\n                .currentScreenName\n        )\n\n        if let pointerDisableAcceleration = scheme.pointer.disableAcceleration, pointerDisableAcceleration {\n            // If the pointer acceleration is turned off, it is preferable to utilize\n            // the new API introduced by macOS Sonoma.\n            // Otherwise, set pointer acceleration to -1.\n            if device.disablePointerAcceleration != nil {\n                device.disablePointerAcceleration = true\n\n                // This might be a bit confusing because of the historical naming\n                // convention, but here, the pointerAcceleration actually refers to\n                // the tracking speed.\n                if let pointerAcceleration = scheme.pointer.acceleration {\n                    switch pointerAcceleration {\n                    case let .value(v):\n                        device.pointerAcceleration = v.asTruncatedDouble\n                    case .unset:\n                        device.restorePointerAcceleration()\n                    }\n                } else {\n                    device.restorePointerAcceleration()\n                }\n            } else {\n                device.pointerAcceleration = -1\n            }\n\n            return\n        }\n\n        if device.disablePointerAcceleration != nil {\n            device.disablePointerAcceleration = false\n        }\n\n        if let pointerSpeed = scheme.pointer.speed {\n            switch pointerSpeed {\n            case let .value(v):\n                device.pointerSpeed = v.asTruncatedDouble\n            case .unset:\n                device.restorePointerSpeed()\n            }\n        } else {\n            device.restorePointerSpeed()\n        }\n\n        if let pointerAcceleration = scheme.pointer.acceleration {\n            switch pointerAcceleration {\n            case let .value(v):\n                device.pointerAcceleration = v.asTruncatedDouble\n            case .unset:\n                device.restorePointerAcceleration()\n            }\n        } else {\n            device.restorePointerAcceleration()\n        }\n    }\n\n    func restorePointerSpeedToInitialValue() {\n        for device in devices {\n            device.restorePointerAccelerationAndPointerSpeed()\n        }\n    }\n\n    func getSystemProperty<T>(forKey key: String) -> T? {\n        let service = IORegistryEntryFromPath(kIOMasterPortDefault, \"\\(kIOServicePlane):/IOResources/IOHIDSystem\")\n        guard service != .zero else {\n            return nil\n        }\n        defer { IOObjectRelease(service) }\n\n        var handle: io_connect_t = .zero\n        guard IOServiceOpen(service, mach_task_self_, UInt32(kIOHIDParamConnectType), &handle) == KERN_SUCCESS else {\n            return nil\n        }\n        defer { IOServiceClose(handle) }\n\n        var valueRef: Unmanaged<CFTypeRef>?\n        guard IOHIDCopyCFTypeParameter(handle, key as CFString, &valueRef) == KERN_SUCCESS else {\n            return nil\n        }\n        guard let valueRefUnwrapped = valueRef else {\n            return nil\n        }\n        guard let value = valueRefUnwrapped.takeRetainedValue() as? T else {\n            return nil\n        }\n        return value\n    }\n\n    func markDeviceActive(_ device: Device, reason: String) {\n        guard lastActiveDeviceId != device.id else {\n            return\n        }\n\n        lastActiveDeviceId = device.id\n        lastActiveDeviceRef = .init(device)\n\n        os_log(\n            \"Last active device changed: %{public}@, category=%{public}@ (Reason: %{public}@)\",\n            log: Self.log,\n            type: .info,\n            String(describing: device),\n            String(describing: device.category),\n            reason\n        )\n\n        updatePointerSpeed()\n    }\n\n    func pairedReceiverDevices(for device: Device) -> [ReceiverLogicalDeviceIdentity] {\n        guard shouldMonitorReceiver(device),\n              let locationID = device.pointerDevice.locationID\n        else {\n            return []\n        }\n\n        let identities = receiverPairedDeviceIdentities[locationID] ?? []\n        os_log(\n            \"Receiver paired device lookup: locationID=%{public}d device=%{public}@ count=%{public}u\",\n            log: Self.log,\n            type: .info,\n            locationID,\n            String(describing: device),\n            UInt32(identities.count)\n        )\n        return identities\n    }\n\n    func preferredName(for device: Device, fallback: String? = nil) -> String {\n        fallback ?? device.name\n    }\n\n    func displayName(for device: Device, fallbackBaseName: String? = nil) -> String {\n        Self.displayName(\n            baseName: preferredName(for: device, fallback: fallbackBaseName),\n            pairedDevices: pairedReceiverDevices(for: device)\n        )\n    }\n\n    private func shouldMonitorReceiver(_ device: Device) -> Bool {\n        guard let vendorID = device.vendorID,\n              vendorID == LogitechHIDPPDeviceMetadataProvider.Constants.vendorID,\n              device.pointerDevice.transport == PointerDeviceTransportName.usb\n        else {\n            return false\n        }\n\n        let productName = device.productName ?? device.name\n        return productName.localizedCaseInsensitiveContains(\"receiver\")\n    }\n\n    private func receiverPointingDevicesChanged(locationID: Int, identities: [ReceiverLogicalDeviceIdentity]) {\n        guard pointerDeviceToDevice.values.contains(where: { $0.pointerDevice.locationID == locationID }) else {\n            os_log(\n                \"Drop receiver logical device update because no visible device matches locationID=%{public}d count=%{public}u\",\n                log: Self.log,\n                type: .info,\n                locationID,\n                UInt32(identities.count)\n            )\n            return\n        }\n\n        let previousIdentities = receiverPairedDeviceIdentities[locationID] ?? []\n        receiverPairedDeviceIdentities[locationID] = identities\n\n        let identitiesDescription = identities.map { identity in\n            let battery = identity.batteryLevel.map(String.init) ?? \"(nil)\"\n            return \"slot=\\(identity.slot) name=\\(identity.name) battery=\\(battery)\"\n        }\n        .joined(separator: \", \")\n\n        os_log(\n            \"Receiver logical devices updated for locationID=%{public}d: %{public}@\",\n            log: Self.log,\n            type: .info,\n            locationID,\n            identitiesDescription\n        )\n\n        // Only trigger forced reconfiguration when a device has actually reconnected\n        // (a slot appeared that wasn't in the previous identity set), since device\n        // firmware resets diversion state on reconnect.\n        let previousSlots = Set(previousIdentities.map(\\.slot))\n        let hasReconnectedDevice = identities.contains { !previousSlots.contains($0.slot) }\n        if hasReconnectedDevice {\n            for (_, device) in pointerDeviceToDevice where device.pointerDevice.locationID == locationID {\n                device.requestLogitechControlsForcedReconfiguration()\n            }\n        }\n    }\n\n    private func refreshVisibleDevices() {\n        devices = pointerDeviceToDevice.values.sorted { $0.id < $1.id }\n    }\n\n    static func displayName(baseName: String, pairedDevices: [ReceiverLogicalDeviceIdentity]) -> String {\n        guard !pairedDevices.isEmpty else {\n            return baseName\n        }\n\n        if pairedDevices.count == 1, let pairedName = pairedDevices.first?.name {\n            return \"\\(baseName) (\\(pairedName))\"\n        }\n\n        return String(\n            format: NSLocalizedString(\"%@ (%lld devices)\", comment: \"\"),\n            baseName,\n            Int64(pairedDevices.count)\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/InputReportHandler.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport Foundation\n\ntypealias MouseButtonEmitter = (_ button: Int, _ down: Bool) -> Void\n\nenum SyntheticMouseButtonEventEmitter {\n    static func post(button: Int, down: Bool) {\n        guard let location = CGEvent(source: nil)?.location,\n              let mouseButton = CGMouseButton(rawValue: UInt32(button)),\n              let event = CGEvent(\n                  mouseEventSource: nil,\n                  mouseType: down ? .otherMouseDown : .otherMouseUp,\n                  mouseCursorPosition: location,\n                  mouseButton: mouseButton\n              ) else {\n            return\n        }\n\n        event.flags = ModifierState.normalize(ModifierState.shared.currentFlags)\n        event.setIntegerValueField(.mouseEventButtonNumber, value: Int64(button))\n        event.isLinearMouseSyntheticEvent = true\n        event.post(tap: .cghidEventTap)\n    }\n}\n\n/// Context passed through the handler chain\nclass InputReportContext {\n    let report: Data\n    var lastButtonStates: UInt8\n\n    init(report: Data, lastButtonStates: UInt8) {\n        self.report = report\n        self.lastButtonStates = lastButtonStates\n    }\n}\n\nprotocol InputReportHandler {\n    /// Check if this handler should be used for the given device\n    func matches(vendorID: Int, productID: Int) -> Bool\n\n    /// Whether report observation is needed regardless of button count\n    /// Most devices only need observation when buttonCount == 3\n    func alwaysNeedsReportObservation() -> Bool\n\n    /// Handle input report and simulate button events as needed\n    /// Call `next(context)` to pass control to the next handler in the chain\n    func handleReport(_ context: InputReportContext, next: (InputReportContext) -> Void)\n}\n\nextension InputReportHandler {\n    func alwaysNeedsReportObservation() -> Bool {\n        false\n    }\n}\n\nenum InputReportHandlerRegistry {\n    static let handlers: [InputReportHandler] = [\n        GenericSideButtonHandler(),\n        KensingtonSlimbladeHandler()\n    ]\n\n    static func handlers(for vendorID: Int, productID: Int) -> [InputReportHandler] {\n        handlers.filter { $0.matches(vendorID: vendorID, productID: productID) }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/InputReportHandlers/GenericSideButtonHandler.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\n/// Handles side button fixes for devices that report only 3 buttons in HID descriptor\n/// but actually have side buttons (button 3 and 4).\n///\n/// Supported devices:\n/// - Mi Dual Mode Wireless Mouse Silent Edition (0x2717:0x5014)\n/// - Delux M729DB mouse (0x248A:0x8266)\nstruct GenericSideButtonHandler: InputReportHandler {\n    private struct Product: Hashable {\n        let vendorID: Int\n        let productID: Int\n    }\n\n    private static let supportedProducts: Set<Product> = [\n        .init(vendorID: 0x2717, productID: 0x5014), // Mi Silent Mouse\n        .init(vendorID: 0x248A, productID: 0x8266) // Delux M729DB mouse\n    ]\n\n    private let emit: MouseButtonEmitter\n\n    init(emit: @escaping MouseButtonEmitter = SyntheticMouseButtonEventEmitter.post) {\n        self.emit = emit\n    }\n\n    func matches(vendorID: Int, productID: Int) -> Bool {\n        Self.supportedProducts.contains(.init(vendorID: vendorID, productID: productID))\n    }\n\n    func handleReport(_ context: InputReportContext, next: (InputReportContext) -> Void) {\n        defer { next(context) }\n\n        guard context.report.count >= 2 else {\n            return\n        }\n\n        // Report format: | Button 0 (1 bit) | ... | Button 4 (1 bit) | Not Used (3 bits) |\n        // We only care about bits 3 and 4 (side buttons)\n        let buttonStates = context.report[1] & 0x18\n        let toggled = context.lastButtonStates ^ buttonStates\n\n        guard toggled != 0 else {\n            return\n        }\n\n        for button in 3 ... 4 {\n            guard toggled & (1 << button) != 0 else {\n                continue\n            }\n            let down = buttonStates & (1 << button) != 0\n            emit(button, down)\n        }\n\n        context.lastButtonStates = buttonStates\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/InputReportHandlers/KensingtonSlimbladeHandler.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\n/// Handles Kensington Slimblade trackball's top buttons.\n///\n/// The Slimblade has vendor-defined buttons that are reported in a different\n/// format than standard HID buttons. This handler parses byte 4 of the input\n/// report to detect top-left and top-right button presses.\n///\n/// Supported devices:\n/// - Kensington Slimblade (0x047D:0x2041)\nstruct KensingtonSlimbladeHandler: InputReportHandler {\n    private static let vendorID = 0x047D\n    private static let productID = 0x2041\n\n    private static let topLeftMask: UInt8 = 0x1\n    private static let topRightMask: UInt8 = 0x2\n\n    private let emit: MouseButtonEmitter\n\n    init(emit: @escaping MouseButtonEmitter = SyntheticMouseButtonEventEmitter.post) {\n        self.emit = emit\n    }\n\n    func matches(vendorID: Int, productID: Int) -> Bool {\n        vendorID == Self.vendorID && productID == Self.productID\n    }\n\n    func alwaysNeedsReportObservation() -> Bool {\n        // Slimblade needs report monitoring regardless of button count\n        true\n    }\n\n    func handleReport(_ context: InputReportContext, next: (InputReportContext) -> Void) {\n        defer { next(context) }\n\n        guard context.report.count >= 5 else {\n            return\n        }\n\n        // For Slimblade, byte 4 contains the vendor-defined button states\n        let buttonStates = context.report[4]\n        let toggled = context.lastButtonStates ^ buttonStates\n\n        guard toggled != 0 else {\n            return\n        }\n\n        // Check top left button (maps to button 3)\n        if toggled & Self.topLeftMask != 0 {\n            let down = buttonStates & Self.topLeftMask != 0\n            emit(3, down)\n        }\n\n        // Check top right button (maps to button 4)\n        if toggled & Self.topRightMask != 0 {\n            let down = buttonStates & Self.topRightMask != 0\n            emit(4, down)\n        }\n\n        context.lastButtonStates = buttonStates\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/ReceiverLogicalDeviceIdentity.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nenum ReceiverLogicalDeviceKind: UInt8, Hashable {\n    case keyboard = 0x01\n    case mouse = 0x02\n    case numpad = 0x03\n    case trackball = 0x08\n    case touchpad = 0x09\n\n    var isPointingDevice: Bool {\n        switch self {\n        case .mouse, .trackball, .touchpad:\n            return true\n        case .keyboard, .numpad:\n            return false\n        }\n    }\n}\n\nstruct ReceiverLogicalDeviceIdentity: Hashable {\n    let receiverLocationID: Int\n    let slot: UInt8\n    let kind: ReceiverLogicalDeviceKind\n    let name: String\n    let serialNumber: String?\n    let productID: Int?\n    let batteryLevel: Int?\n\n    func isSameLogicalDevice(as other: Self) -> Bool {\n        receiverLocationID == other.receiverLocationID && slot == other.slot\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/ReceiverMonitor.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nfinal class ReceiverMonitor {\n    static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"ReceiverMonitor\")\n    static let initialDiscoveryTimeout: TimeInterval = 3\n    static let refreshInterval: TimeInterval = 15\n\n    private let provider = LogitechHIDPPDeviceMetadataProvider()\n    private var contexts = [Int: ReceiverContext]()\n\n    var onPointingDevicesChanged: ((Int, [ReceiverLogicalDeviceIdentity]) -> Void)?\n\n    func startMonitoring(device: Device) {\n        guard let locationID = device.pointerDevice.locationID else {\n            return\n        }\n\n        guard contexts[locationID] == nil else {\n            return\n        }\n\n        let context = ReceiverContext(device: device, locationID: locationID, provider: provider)\n        context.onDiscoveryTimedOut = { [weak self, weak context] in\n            guard let self,\n                  let context,\n                  self.contexts[locationID] === context\n            else {\n                return\n            }\n\n            self.onPointingDevicesChanged?(locationID, [])\n        }\n        context.onSlotsChanged = { [weak self, weak context] identities in\n            guard let self,\n                  let context,\n                  self.contexts[locationID] === context\n            else {\n                return\n            }\n\n            self.onPointingDevicesChanged?(locationID, identities)\n        }\n        contexts[locationID] = context\n        context.start()\n\n        os_log(\"Started receiver monitor for %{public}@\", log: Self.log, type: .info, String(describing: device))\n    }\n\n    func stopMonitoring(device: Device) {\n        guard let locationID = device.pointerDevice.locationID,\n              let context = contexts.removeValue(forKey: locationID)\n        else {\n            return\n        }\n\n        context.stop()\n    }\n}\n\nstruct ReceiverSlotStateStore {\n    enum SlotPresenceState {\n        case unknown\n        case connected\n        case disconnected\n    }\n\n    private var pairedIdentitiesBySlot = [UInt8: ReceiverLogicalDeviceIdentity]()\n    private var slotPresenceBySlot = [UInt8: SlotPresenceState]()\n\n    mutating func reset() {\n        pairedIdentitiesBySlot = [:]\n        slotPresenceBySlot = [:]\n    }\n\n    mutating func mergeDiscovery(_ discovery: LogitechHIDPPDeviceMetadataProvider.ReceiverPointingDeviceDiscovery) {\n        let latestIdentitiesBySlot = Dictionary(uniqueKeysWithValues: discovery.identities.map {\n            ($0.slot, $0)\n        })\n        let previousIdentitiesBySlot = pairedIdentitiesBySlot\n\n        for slot in pairedIdentitiesBySlot.keys where latestIdentitiesBySlot[slot] == nil {\n            pairedIdentitiesBySlot.removeValue(forKey: slot)\n            slotPresenceBySlot.removeValue(forKey: slot)\n        }\n\n        for (slot, identity) in latestIdentitiesBySlot {\n            pairedIdentitiesBySlot[slot] = identity\n            if slotPresenceBySlot[slot] == nil {\n                slotPresenceBySlot[slot] = .unknown\n            }\n        }\n\n        mergeConnectionSnapshots(discovery.connectionSnapshots)\n\n        for slot in discovery.liveReachableSlots {\n            if slotPresenceBySlot[slot] != .connected {\n                slotPresenceBySlot[slot] = .connected\n            }\n        }\n\n        for (slot, identity) in latestIdentitiesBySlot where discovery.connectionSnapshots[slot] == nil {\n            guard slotPresenceBySlot[slot] == .disconnected,\n                  previousIdentitiesBySlot[slot]?.batteryLevel == nil,\n                  identity.batteryLevel != nil,\n                  !discovery.liveReachableSlots.contains(slot)\n            else {\n                continue\n            }\n\n            slotPresenceBySlot[slot] = .connected\n        }\n    }\n\n    mutating func mergeConnectionSnapshots(\n        _ newSnapshots: [UInt8: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot]\n    ) {\n        for (slot, snapshot) in newSnapshots {\n            let newPresence: SlotPresenceState = snapshot.isConnected ? .connected : .disconnected\n            let oldPresence = slotPresenceBySlot[slot]\n            slotPresenceBySlot[slot] = newPresence\n\n            // Clear stale identity when a device reconnects to a slot,\n            // so the next needsIdentityRefresh check will trigger a refresh.\n            if newPresence == .connected, oldPresence == .disconnected {\n                pairedIdentitiesBySlot.removeValue(forKey: slot)\n            }\n        }\n    }\n\n    mutating func updateSlotIdentity(_ identity: ReceiverLogicalDeviceIdentity) {\n        pairedIdentitiesBySlot[identity.slot] = identity\n        slotPresenceBySlot[identity.slot] = .connected\n    }\n\n    func needsIdentityRefresh(slot: UInt8) -> Bool {\n        pairedIdentitiesBySlot[slot] == nil\n    }\n\n    func currentPublishedIdentities() -> [ReceiverLogicalDeviceIdentity] {\n        pairedIdentitiesBySlot.keys.sorted().compactMap { slot in\n            guard let identity = pairedIdentitiesBySlot[slot] else {\n                return nil\n            }\n\n            return slotPresenceBySlot[slot] == .disconnected ? nil : identity\n        }\n    }\n}\n\nprivate final class ReceiverContext {\n    let device: Device\n    private let locationID: Int\n    private let provider: LogitechHIDPPDeviceMetadataProvider\n    private var workerThread: Thread?\n    private var isRunning = false\n    private let stateLock = NSLock()\n    private var lastPublishedIdentities = [ReceiverLogicalDeviceIdentity]()\n    private var stateStore = ReceiverSlotStateStore()\n\n    var onDiscoveryTimedOut: (() -> Void)?\n    var onSlotsChanged: (([ReceiverLogicalDeviceIdentity]) -> Void)?\n    init(device: Device, locationID: Int, provider: LogitechHIDPPDeviceMetadataProvider) {\n        self.device = device\n        self.locationID = locationID\n        self.provider = provider\n    }\n\n    func start() {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n\n        guard !isRunning else {\n            return\n        }\n        isRunning = true\n        lastPublishedIdentities = []\n        stateStore.reset()\n\n        let thread = Thread { [weak self] in\n            self?.workerMain()\n        }\n        thread.name = \"linearmouse.receiver-monitor.\\(locationID)\"\n        workerThread = thread\n        thread.start()\n    }\n\n    func stop() {\n        stateLock.lock()\n        isRunning = false\n        let thread = workerThread\n        workerThread = nil\n        stateLock.unlock()\n\n        thread?.cancel()\n    }\n\n    private func workerMain() {\n        let initialDeadline = Date().addingTimeInterval(ReceiverMonitor.initialDiscoveryTimeout)\n        var hasPublishedInitialState = false\n        var currentChannel: LogitechReceiverChannel?\n        var hasCompletedInitialDiscovery = false\n\n        while shouldContinueRunning() {\n            if currentChannel == nil {\n                currentChannel = provider.openReceiverChannel(for: device.pointerDevice)\n                hasCompletedInitialDiscovery = false\n            }\n\n            guard let receiverChannel = currentChannel else {\n                os_log(\n                    \"Receiver monitor is waiting for channel: locationID=%{public}d device=%{public}@\",\n                    log: ReceiverMonitor.log,\n                    type: .info,\n                    locationID,\n                    String(describing: device)\n                )\n\n                if !hasPublishedInitialState, Date() >= initialDeadline {\n                    DispatchQueue.main.async { [weak self] in\n                        self?.onDiscoveryTimedOut?()\n                    }\n                    hasPublishedInitialState = true\n                }\n\n                CFRunLoopRunInMode(.defaultMode, 0.5, true)\n                continue\n            }\n\n            // Full discovery only once per channel open\n            if !hasCompletedInitialDiscovery {\n                let discovery = provider.receiverPointingDeviceDiscovery(\n                    for: device.pointerDevice, using: receiverChannel\n                )\n                mergeDiscovery(discovery)\n                hasCompletedInitialDiscovery = true\n\n                let identities = currentPublishedIdentities()\n                let identitiesDescription = identities.map { identity in\n                    let battery = identity.batteryLevel.map(String.init) ?? \"(nil)\"\n                    return \"slot=\\(identity.slot) name=\\(identity.name) battery=\\(battery)\"\n                }\n                .joined(separator: \", \")\n\n                os_log(\n                    \"Receiver initial discovery completed: locationID=%{public}d count=%{public}u identities=%{public}@\",\n                    log: ReceiverMonitor.log,\n                    type: .info,\n                    locationID,\n                    UInt32(identities.count),\n                    identitiesDescription\n                )\n\n                if identities != lastPublishedIdentities {\n                    publish(identities)\n                    hasPublishedInitialState = true\n                } else if !hasPublishedInitialState, !identities.isEmpty {\n                    publish(identities)\n                    hasPublishedInitialState = true\n                } else if !hasPublishedInitialState, Date() >= initialDeadline {\n                    os_log(\n                        \"Receiver logical discovery timed out: locationID=%{public}d device=%{public}@\",\n                        log: ReceiverMonitor.log,\n                        type: .info,\n                        locationID,\n                        String(describing: device)\n                    )\n                    DispatchQueue.main.async { [weak self] in\n                        self?.onDiscoveryTimedOut?()\n                    }\n                    hasPublishedInitialState = true\n                }\n            }\n\n            // Wait for connection events (event-driven, no periodic rescan)\n            let connectionSnapshots = provider.waitForReceiverConnectionChange(\n                using: receiverChannel,\n                timeout: ReceiverMonitor.refreshInterval\n            ) { [weak self] in\n                self?.shouldContinueRunning() ?? false\n            }\n\n            if !shouldContinueRunning() {\n                break\n            }\n\n            guard !connectionSnapshots.isEmpty else {\n                // Timeout with no events — verify channel is still alive\n                if receiverChannel.readNotificationFlags() == nil {\n                    os_log(\n                        \"Receiver channel appears dead, will reopen: locationID=%{public}d device=%{public}@\",\n                        log: ReceiverMonitor.log,\n                        type: .info,\n                        locationID,\n                        String(describing: device)\n                    )\n                    currentChannel = nil\n                }\n                continue\n            }\n\n            mergeConnectionSnapshots(connectionSnapshots)\n\n            // For newly connected devices, read their identity info\n            for (slot, snapshot) in connectionSnapshots where snapshot.isConnected {\n                if needsIdentityRefresh(slot: slot) {\n                    refreshSlotIdentity(\n                        slot: slot,\n                        connectionSnapshot: snapshot,\n                        using: receiverChannel\n                    )\n                }\n            }\n\n            let snapshotDescription = connectionSnapshots.keys\n                .sorted()\n                .compactMap { slot -> String? in\n                    guard let snapshot = connectionSnapshots[slot] else {\n                        return nil\n                    }\n\n                    return \"slot=\\(slot) connected=\\(snapshot.isConnected)\"\n                }\n                .joined(separator: \", \")\n\n            os_log(\n                \"Receiver connection change detected: locationID=%{public}d device=%{public}@ snapshots=%{public}@\",\n                log: ReceiverMonitor.log,\n                type: .info,\n                locationID,\n                String(describing: device),\n                snapshotDescription\n            )\n\n            let identities = currentPublishedIdentities()\n            if identities != lastPublishedIdentities {\n                publish(identities)\n            }\n        }\n    }\n\n    private func publish(_ identities: [ReceiverLogicalDeviceIdentity]) {\n        lastPublishedIdentities = identities\n\n        let identitiesDescription = identities.map { identity in\n            let battery = identity.batteryLevel.map(String.init) ?? \"(nil)\"\n            return \"slot=\\(identity.slot) name=\\(identity.name) battery=\\(battery)\"\n        }\n        .joined(separator: \", \")\n\n        os_log(\n            \"Receiver logical discovery updated: locationID=%{public}d identities=%{public}@\",\n            log: ReceiverMonitor.log,\n            type: .info,\n            locationID,\n            identitiesDescription\n        )\n\n        DispatchQueue.main.async { [weak self] in\n            self?.onSlotsChanged?(identities)\n        }\n    }\n\n    private func shouldContinueRunning() -> Bool {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n        return isRunning\n    }\n\n    private func mergeDiscovery(_ discovery: LogitechHIDPPDeviceMetadataProvider.ReceiverPointingDeviceDiscovery) {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n        stateStore.mergeDiscovery(discovery)\n    }\n\n    private func mergeConnectionSnapshots(\n        _ newSnapshots: [UInt8: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot]\n    ) {\n        guard !newSnapshots.isEmpty else {\n            return\n        }\n\n        stateLock.lock()\n        stateStore.mergeConnectionSnapshots(newSnapshots)\n        stateLock.unlock()\n    }\n\n    private func refreshSlotIdentity(\n        slot: UInt8,\n        connectionSnapshot: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot?,\n        using receiverChannel: LogitechReceiverChannel\n    ) {\n        guard let identity = provider.receiverSlotIdentity(\n            for: device.pointerDevice,\n            slot: slot,\n            connectionSnapshot: connectionSnapshot,\n            using: receiverChannel\n        ) else {\n            return\n        }\n\n        stateLock.lock()\n        stateStore.updateSlotIdentity(identity)\n        stateLock.unlock()\n\n        os_log(\n            \"Refreshed slot identity: locationID=%{public}d slot=%{public}u name=%{public}@ battery=%{public}@\",\n            log: ReceiverMonitor.log,\n            type: .info,\n            locationID,\n            slot,\n            identity.name,\n            identity.batteryLevel.map(String.init) ?? \"(nil)\"\n        )\n    }\n\n    private func needsIdentityRefresh(slot: UInt8) -> Bool {\n        stateLock.lock()\n        let needs = stateStore.needsIdentityRefresh(slot: slot)\n        stateLock.unlock()\n        return needs\n    }\n\n    private func currentPublishedIdentities() -> [ReceiverLogicalDeviceIdentity] {\n        stateLock.lock()\n        let identities = stateStore.currentPublishedIdentities()\n        stateLock.unlock()\n        return identities\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/VendorSpecific/BatteryDeviceMonitor.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\n\nfinal class BatteryDeviceMonitor: NSObject, ObservableObject {\n    static let shared = BatteryDeviceMonitor()\n\n    @Published private(set) var devices: [ConnectedBatteryDeviceInfo] = []\n\n    private static let pollingInterval: TimeInterval = 60\n\n    private let queue = DispatchQueue(label: \"linearmouse.battery-monitor\", qos: .utility)\n    private let timerQueue = DispatchQueue(label: \"linearmouse.battery-monitor.timer\", qos: .utility)\n\n    private var timer: DispatchSourceTimer?\n    private var isRunning = false\n    private var isRefreshing = false\n    private var needsRefresh = false\n    private let stateLock = NSLock()\n    private var subscriptions = Set<AnyCancellable>()\n\n    override init() {\n        super.init()\n\n        DeviceManager.shared\n            .$devices\n            .receive(on: RunLoop.main)\n            .debounce(for: .milliseconds(250), scheduler: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.refreshIfNeeded()\n            }\n            .store(in: &subscriptions)\n\n        DeviceManager.shared\n            .$receiverPairedDeviceIdentities\n            .receive(on: RunLoop.main)\n            .debounce(for: .milliseconds(250), scheduler: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.refreshIfNeeded()\n            }\n            .store(in: &subscriptions)\n    }\n\n    func start() {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n\n        guard !isRunning else {\n            return\n        }\n        isRunning = true\n\n        let timer = DispatchSource.makeTimerSource(queue: timerQueue)\n        timer.schedule(deadline: .now(), repeating: Self.pollingInterval)\n        timer.setEventHandler { [weak self] in\n            self?.refreshIfNeeded()\n        }\n        self.timer = timer\n        timer.resume()\n    }\n\n    func stop() {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n\n        guard isRunning else {\n            return\n        }\n\n        isRunning = false\n        timer?.setEventHandler {}\n        timer?.cancel()\n        timer = nil\n    }\n\n    func currentDeviceBatteryLevel(for device: Device) -> Int? {\n        let pairedDevices = DeviceManager.shared.pairedReceiverDevices(for: device)\n        let directDeviceIdentity = ConnectedBatteryDeviceInfo.directIdentity(\n            vendorID: device.vendorID,\n            productID: device.productID,\n            serialNumber: device.serialNumber,\n            locationID: device.pointerDevice.locationID,\n            transport: device.pointerDevice.transport,\n            fallbackName: device.productName ?? device.name\n        )\n\n        return ConnectedBatteryDeviceInfo.currentDeviceBatteryLevel(\n            pairedDevices: pairedDevices,\n            directDeviceIdentity: directDeviceIdentity,\n            inventory: devices\n        )\n    }\n\n    private func refreshIfNeeded() {\n        stateLock.lock()\n        guard isRunning, !isRefreshing else {\n            if isRunning {\n                needsRefresh = true\n            }\n            stateLock.unlock()\n            return\n        }\n        isRefreshing = true\n        needsRefresh = false\n        stateLock.unlock()\n\n        queue.async { [weak self] in\n            guard let self else {\n                return\n            }\n\n            let receiverPairedBatteries = DeviceManager.shared.devices.flatMap { device in\n                DeviceManager.shared\n                    .pairedReceiverDevices(for: device)\n                    .compactMap { identity -> ConnectedBatteryDeviceInfo? in\n                        guard let batteryLevel = identity.batteryLevel else {\n                            return nil\n                        }\n\n                        return ConnectedBatteryDeviceInfo(\n                            id: ConnectedBatteryDeviceInfo.receiverIdentity(\n                                receiverLocationID: identity.receiverLocationID,\n                                slot: identity.slot\n                            ),\n                            name: identity.name,\n                            batteryLevel: batteryLevel\n                        )\n                    }\n            }\n            let visibleDeviceBatteries = DeviceManager.shared\n                .devices\n                .compactMap { device -> ConnectedBatteryDeviceInfo? in\n                    guard DeviceManager.shared.pairedReceiverDevices(for: device).isEmpty,\n                          let batteryLevel = device.batteryLevel\n                    else {\n                        return nil\n                    }\n\n                    return ConnectedBatteryDeviceInfo(\n                        id: ConnectedBatteryDeviceInfo.directIdentity(\n                            vendorID: device.vendorID,\n                            productID: device.productID,\n                            serialNumber: device.serialNumber,\n                            locationID: device.pointerDevice.locationID,\n                            transport: device.pointerDevice.transport,\n                            fallbackName: device.productName ?? device.name\n                        ),\n                        name: device.name,\n                        batteryLevel: batteryLevel\n                    )\n                }\n            let propertyBackedDevices = ConnectedBatteryDeviceInventory.devices()\n            let directlyAddressableLogitechDevices = DeviceManager.shared.devices.filter {\n                DeviceManager.shared.pairedReceiverDevices(for: $0).isEmpty\n            }\n            let logitechDevices = ConnectedLogitechDeviceInventory\n                .devices(from: directlyAddressableLogitechDevices.map(\\.pointerDevice))\n            DispatchQueue.main.async {\n                self.devices = self.merge(\n                    logitechDevices: receiverPairedBatteries + visibleDeviceBatteries + logitechDevices,\n                    propertyBackedDevices: propertyBackedDevices\n                )\n            }\n\n            self.finishRefreshCycle()\n        }\n    }\n\n    private func finishRefreshCycle() {\n        stateLock.lock()\n        isRefreshing = false\n        let shouldRefreshAgain = needsRefresh\n        needsRefresh = false\n        stateLock.unlock()\n\n        if shouldRefreshAgain {\n            refreshIfNeeded()\n        }\n    }\n\n    private func merge(\n        logitechDevices: [ConnectedBatteryDeviceInfo],\n        propertyBackedDevices: [ConnectedBatteryDeviceInfo]\n    ) -> [ConnectedBatteryDeviceInfo] {\n        var merged = [ConnectedBatteryDeviceInfo]()\n        var seen = Set<String>()\n\n        for device in logitechDevices + propertyBackedDevices {\n            guard seen.insert(device.id).inserted else {\n                continue\n            }\n\n            merged.append(device)\n        }\n\n        return merged.sorted {\n            let byName = $0.name.localizedCaseInsensitiveCompare($1.name)\n            if byName == .orderedSame {\n                return $0.batteryLevel > $1.batteryLevel\n            }\n\n            return byName == .orderedAscending\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/VendorSpecific/ConnectedBatteryDeviceInventory.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport IOKit.hid\nimport PointerKit\n\nprivate typealias AppleBatterySnapshot = (id: String, level: Int)\n\nstruct ConnectedBatteryDeviceInfo: Hashable {\n    let id: String\n    let name: String\n    let batteryLevel: Int\n\n    static func directIdentity(\n        vendorID: Int?,\n        productID: Int?,\n        serialNumber: String?,\n        locationID: Int?,\n        transport: String?,\n        fallbackName: String\n    ) -> String {\n        if let serialNumber, !serialNumber.isEmpty {\n            return \"serial|\\(vendorID ?? 0)|\\(productID ?? 0)|\\(serialNumber)\"\n        }\n\n        if let locationID {\n            return \"location|\\(vendorID ?? 0)|\\(productID ?? 0)|\\(locationID)\"\n        }\n\n        return \"fallback|\\(transport ?? \"\")|\\(vendorID ?? 0)|\\(productID ?? 0)|\\(fallbackName)\"\n    }\n\n    static func receiverIdentity(receiverLocationID: Int, slot: UInt8) -> String {\n        \"receiver|\\(receiverLocationID)|\\(slot)\"\n    }\n\n    static func currentDeviceBatteryLevel(\n        pairedDevices: [ReceiverLogicalDeviceIdentity],\n        directDeviceIdentity: String?,\n        inventory: [Self]\n    ) -> Int? {\n        let pairedBatteryLevels = pairedDevices.compactMap(\\.batteryLevel)\n        if let lowestPairedBatteryLevel = pairedBatteryLevels.min() {\n            return lowestPairedBatteryLevel\n        }\n\n        guard let directDeviceIdentity else {\n            return nil\n        }\n\n        return inventory.first { $0.id == directDeviceIdentity }?.batteryLevel\n    }\n\n    static func isAppleBluetoothDevice(vendorID: Int?, transport: String?) -> Bool {\n        vendorID == 0x004C && transport == PointerDeviceTransportName.bluetooth\n    }\n}\n\nenum ConnectedBatteryDeviceInventory {\n    static func devices() -> [ConnectedBatteryDeviceInfo] {\n        let manager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))\n        IOHIDManagerSetDeviceMatching(manager, nil)\n\n        guard IOHIDManagerOpen(manager, IOOptionBits(kIOHIDOptionsTypeNone)) == kIOReturnSuccess else {\n            return []\n        }\n\n        defer {\n            IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone))\n        }\n\n        guard let hidDevices = IOHIDManagerCopyDevices(manager) as? Set<IOHIDDevice> else {\n            return []\n        }\n\n        var results = [ConnectedBatteryDeviceInfo]()\n        var seen = Set<String>()\n        let appleBatterySnapshots = appleBluetoothBatterySnapshots()\n\n        for hidDevice in hidDevices {\n            guard let result = batteryDeviceInfo(for: hidDevice, appleBatterySnapshots: appleBatterySnapshots) else {\n                continue\n            }\n\n            guard seen.insert(result.id).inserted else {\n                continue\n            }\n\n            results.append(result)\n        }\n\n        return results.sorted {\n            let byName = $0.name.localizedCaseInsensitiveCompare($1.name)\n            if byName == .orderedSame {\n                return $0.batteryLevel > $1.batteryLevel\n            }\n\n            return byName == .orderedAscending\n        }\n    }\n\n    private static func batteryDeviceInfo(\n        for hidDevice: IOHIDDevice,\n        appleBatterySnapshots: [AppleBatterySnapshot]\n    ) -> ConnectedBatteryDeviceInfo? {\n        let vendorID: NSNumber? = getProperty(kIOHIDVendorIDKey, from: hidDevice)\n        let productID: NSNumber? = getProperty(kIOHIDProductIDKey, from: hidDevice)\n        let serialNumber: String? = getProperty(kIOHIDSerialNumberKey, from: hidDevice)\n        let locationID: NSNumber? = getProperty(\"LocationID\", from: hidDevice)\n        let transport: String? = getProperty(\"Transport\", from: hidDevice)\n\n        let candidateKeys = [\n            \"BatteryPercent\",\n            \"BatteryLevel\",\n            \"BatteryPercentRemaining\",\n            \"BatteryPercentSingle\"\n        ]\n\n        let directBatteryLevel = candidateKeys.lazy\n            .compactMap { key -> Int? in\n                if let value: NSNumber = getProperty(key, from: hidDevice) {\n                    return value.intValue\n                }\n\n                return nil\n            }\n            .first\n\n        let batteryLevel = directBatteryLevel\n            ?? fallbackAppleBluetoothBatteryLevel(\n                vendorID: vendorID?.intValue,\n                productID: productID?.intValue,\n                serialNumber: serialNumber,\n                locationID: locationID?.intValue,\n                transport: transport,\n                appleBatterySnapshots: appleBatterySnapshots\n            )\n\n        guard let batteryLevel else {\n            return nil\n        }\n\n        let name: String = getProperty(kIOHIDProductKey, from: hidDevice) ?? \"(unknown)\"\n\n        if isGenericLogitechReceiver(name: name, hidDevice: hidDevice) {\n            return nil\n        }\n\n        return ConnectedBatteryDeviceInfo(\n            id: ConnectedBatteryDeviceInfo.directIdentity(\n                vendorID: vendorID?.intValue,\n                productID: productID?.intValue,\n                serialNumber: serialNumber,\n                locationID: locationID?.intValue,\n                transport: transport,\n                fallbackName: name\n            ),\n            name: name,\n            batteryLevel: batteryLevel\n        )\n    }\n\n    private static func isGenericLogitechReceiver(name: String, hidDevice: IOHIDDevice) -> Bool {\n        guard let vendorID: NSNumber = getProperty(kIOHIDVendorIDKey, from: hidDevice),\n              vendorID.intValue == 0x046D\n        else {\n            return false\n        }\n\n        return name.localizedCaseInsensitiveContains(\"receiver\")\n    }\n\n    private static func getProperty<T>(_ key: String, from device: IOHIDDevice) -> T? {\n        guard let value = IOHIDDeviceGetProperty(device, key as CFString) else {\n            return nil\n        }\n\n        return value as? T\n    }\n\n    private static func fallbackAppleBluetoothBatteryLevel(\n        vendorID: Int?,\n        productID: Int?,\n        serialNumber: String?,\n        locationID: Int?,\n        transport: String?,\n        appleBatterySnapshots: [AppleBatterySnapshot]\n    ) -> Int? {\n        guard ConnectedBatteryDeviceInfo.isAppleBluetoothDevice(vendorID: vendorID, transport: transport) else {\n            return nil\n        }\n\n        let directID = ConnectedBatteryDeviceInfo.directIdentity(\n            vendorID: vendorID,\n            productID: productID,\n            serialNumber: serialNumber,\n            locationID: locationID,\n            transport: transport,\n            fallbackName: \"\"\n        )\n\n        return appleBatterySnapshots.first { $0.id == directID }?.level\n    }\n\n    private static func appleBluetoothBatterySnapshots() -> [AppleBatterySnapshot] {\n        var snapshots = [AppleBatterySnapshot]()\n        var iterator = io_iterator_t()\n\n        guard IOServiceGetMatchingServices(\n            kIOMasterPortDefault,\n            IOServiceMatching(\"AppleDeviceManagementHIDEventService\"),\n            &iterator\n        ) == KERN_SUCCESS else {\n            return []\n        }\n\n        defer { IOObjectRelease(iterator) }\n\n        var service = IOIteratorNext(iterator)\n        while service != MACH_PORT_NULL {\n            defer {\n                IOObjectRelease(service)\n                service = IOIteratorNext(iterator)\n            }\n\n            guard let vendorIDNumber = IORegistryEntryCreateCFProperty(\n                service,\n                kIOHIDVendorIDKey as CFString,\n                kCFAllocatorDefault,\n                0\n            )?.takeRetainedValue() as? NSNumber,\n                let transport = IORegistryEntryCreateCFProperty(\n                    service,\n                    \"Transport\" as CFString,\n                    kCFAllocatorDefault,\n                    0\n                )?.takeRetainedValue() as? String,\n                let batteryLevel = IORegistryEntryCreateCFProperty(\n                    service,\n                    \"BatteryPercent\" as CFString,\n                    kCFAllocatorDefault,\n                    0\n                )?.takeRetainedValue() as? NSNumber,\n                ConnectedBatteryDeviceInfo.isAppleBluetoothDevice(\n                    vendorID: vendorIDNumber.intValue,\n                    transport: transport\n                )\n            else {\n                continue\n            }\n\n            let productID = (IORegistryEntryCreateCFProperty(\n                service,\n                kIOHIDProductIDKey as CFString,\n                kCFAllocatorDefault,\n                0\n            )?.takeRetainedValue() as? NSNumber)?.intValue\n            let serialNumber = IORegistryEntryCreateCFProperty(\n                service,\n                kIOHIDSerialNumberKey as CFString,\n                kCFAllocatorDefault,\n                0\n            )?.takeRetainedValue() as? String\n            let locationID = (IORegistryEntryCreateCFProperty(\n                service,\n                \"LocationID\" as CFString,\n                kCFAllocatorDefault,\n                0\n            )?.takeRetainedValue() as? NSNumber)?.intValue\n\n            let id = ConnectedBatteryDeviceInfo.directIdentity(\n                vendorID: vendorIDNumber.intValue,\n                productID: productID,\n                serialNumber: serialNumber,\n                locationID: locationID,\n                transport: transport,\n                fallbackName: \"\"\n            )\n            snapshots.append((id: id, level: batteryLevel.intValue))\n        }\n\n        return snapshots\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/VendorSpecific/ConnectedLogitechDeviceInventory.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport PointerKit\n\nenum ConnectedLogitechDeviceInventory {\n    static func devices(from pointerDevices: [PointerDevice]) -> [ConnectedBatteryDeviceInfo] {\n        var results = [ConnectedBatteryDeviceInfo]()\n        var seen = Set<String>()\n\n        for device in pointerDevices where device.vendorID == LogitechHIDPPDeviceMetadataProvider.Constants.vendorID {\n            let productName = device.product ?? device.name\n            if device.transport == PointerDeviceTransportName.usb,\n               productName.localizedCaseInsensitiveContains(\"receiver\") {\n                continue\n            }\n\n            guard let metadata = VendorSpecificDeviceMetadataRegistry.metadata(for: device),\n                  let batteryLevel = metadata.batteryLevel\n            else {\n                continue\n            }\n\n            let name = metadata.name ?? productName\n            let identity = ConnectedBatteryDeviceInfo.directIdentity(\n                vendorID: device.vendorID,\n                productID: device.productID,\n                serialNumber: device.serialNumber,\n                locationID: device.locationID,\n                transport: device.transport,\n                fallbackName: name\n            )\n            guard seen.insert(identity).inserted else {\n                continue\n            }\n\n            results.append(.init(id: identity, name: name, batteryLevel: batteryLevel))\n        }\n\n        return results.sorted {\n            let byName = $0.name.localizedCaseInsensitiveCompare($1.name)\n            if byName == .orderedSame {\n                return $0.batteryLevel > $1.batteryLevel\n            }\n\n            return byName == .orderedAscending\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/VendorSpecific/Logitech/LogitechHIDPPDeviceMetadataProvider.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Combine\nimport Foundation\nimport IOKit.hid\nimport ObservationToken\nimport os.log\nimport PointerKit\n\nstruct LogitechHIDPPDeviceMetadataProvider: VendorSpecificDeviceMetadataProvider {\n    static let log = OSLog(\n        subsystem: Bundle.main.bundleIdentifier ?? \"LinearMouse\",\n        category: \"LogitechHIDPP\"\n    )\n\n    enum Constants {\n        static let vendorID = 0x046D\n        static let softwareID: UInt8 = 0x08\n        static let shortReportID: UInt8 = 0x10\n        static let longReportID: UInt8 = 0x11\n        static let shortReportLength = 7\n        static let longReportLength = 20\n        static let timeout: TimeInterval = 2.0\n\n        static let receiverIndex: UInt8 = 0xFF\n        static let directReplyIndices: Set<UInt8> = [0x00, 0xFF]\n        static let receiverNotificationFlagsRegister: UInt8 = 0x00\n        static let receiverConnectionStateRegister: UInt8 = 0x02\n        static let receiverInfoRegister: UInt8 = 0xB5\n        static let receiverWirelessNotifications: UInt32 = 0x000100\n        static let receiverSoftwarePresentNotifications: UInt32 = 0x000800\n    }\n\n    enum FeatureID: UInt16 {\n        case root = 0x0000\n        case deviceName = 0x0005\n        case deviceFriendlyName = 0x0007\n        case batteryStatus = 0x1000\n        case batteryVoltage = 0x1001\n        case unifiedBattery = 0x1004\n        case reprogControlsV4 = 0x1B04\n        case adcMeasurement = 0x1F20\n    }\n\n    enum ReprogControlsV4 {\n        static let gestureButtonControlIDs: Set<UInt16> = [0x00C3, 0x00D0]\n        static let virtualGestureButtonControlIDs: Set<UInt16> = [0x00D7]\n        static let gestureButtonTaskIDs: Set<UInt16> = [0x009C, 0x00A9, 0x00AD]\n        static let virtualGestureButtonTaskIDs: Set<UInt16> = [0x00B4]\n        /// Control IDs that should never be diverted because they are natively handled by the OS.\n        /// Diverting these would break their default behavior (click, back/forward, etc.).\n        static let nativeControlIDs: Set<UInt16> = [\n            0x0050, 0x0051, 0x0052, // Left / right / middle mouse button\n            0x0053, 0x0056, // Standard back/forward\n            0x00CE, 0x00CF, // Alternate back/forward\n            0x00D9, 0x00DB // Additional back/forward variants\n        ]\n        /// Reserved button number written into config for virtual controls.\n        /// Older versions do not generate this button, so persisted mappings will not misfire after downgrade.\n        /// This value is intentionally vendor-agnostic so other protocol-backed controls can reuse it later.\n        static let reservedVirtualButtonNumber = 0x1000\n\n        static let getControlCountFunction: UInt8 = 0x00\n        static let getControlInfoFunction: UInt8 = 0x01\n        static let getControlReportingFunction: UInt8 = 0x02\n        static let setControlReportingFunction: UInt8 = 0x03\n\n        struct ControlFlags: OptionSet {\n            let rawValue: UInt16\n\n            static let mouseButton = Self(rawValue: 1 << 0)\n            static let reprogrammable = Self(rawValue: 1 << 4)\n            static let divertable = Self(rawValue: 1 << 5)\n            static let persistentlyDivertable = Self(rawValue: 1 << 6)\n            static let virtual = Self(rawValue: 1 << 7)\n            static let rawXY = Self(rawValue: 1 << 8)\n            static let forceRawXY = Self(rawValue: 1 << 9)\n        }\n\n        struct ReportingFlags: OptionSet {\n            let rawValue: UInt16\n\n            static let diverted = Self(rawValue: 1 << 0)\n            static let persistentlyDiverted = Self(rawValue: 1 << 2)\n            static let rawXYDiverted = Self(rawValue: 1 << 4)\n            static let forceRawXYDiverted = Self(rawValue: 1 << 6)\n        }\n    }\n\n    private enum DeviceKind: UInt8 {\n        case keyboard = 0x01\n        case mouse = 0x02\n        case trackball = 0x08\n        case touchpad = 0x09\n    }\n\n    struct Response {\n        let payload: [UInt8]\n    }\n\n    struct ReceiverSlotInfo {\n        let slot: UInt8\n        let kind: UInt8\n        let name: String?\n        let productID: Int?\n        let serialNumber: String?\n        let batteryLevel: Int?\n        let hasLiveMetadata: Bool\n    }\n\n    struct ReceiverSlotMetadata {\n        let slot: UInt8\n        let name: String?\n        let batteryLevel: Int?\n    }\n\n    struct ReceiverConnectionSnapshot: Equatable {\n        let isConnected: Bool\n        let kind: UInt8?\n    }\n\n    struct ReceiverSlotDiscovery {\n        let slots: [ReceiverSlotInfo]\n        let connectionSnapshots: [UInt8: ReceiverConnectionSnapshot]\n    }\n\n    struct ReceiverPointingDeviceDiscovery {\n        let identities: [ReceiverLogicalDeviceIdentity]\n        let connectionSnapshots: [UInt8: ReceiverConnectionSnapshot]\n        let liveReachableSlots: Set<UInt8>\n    }\n\n    struct ReceiverSlotMatchCandidate {\n        let slot: UInt8\n        let kind: UInt8\n        let name: String?\n        let serialNumber: String?\n        let productID: Int?\n        let batteryLevel: Int?\n        let hasLiveMetadata: Bool\n    }\n\n    private enum ApproximateBatteryLevel: UInt8 {\n        case full = 8\n        case good = 4\n        case low = 2\n        case critical = 1\n\n        var percent: Int {\n            switch self {\n            case .full:\n                return 100\n            case .good:\n                return 50\n            case .low:\n                return 20\n            case .critical:\n                return 5\n            }\n        }\n    }\n\n    let matcher = VendorSpecificDeviceMatcher(\n        vendorID: Constants.vendorID,\n        productIDs: nil,\n        transports: [PointerDeviceTransportName.bluetoothLowEnergy, PointerDeviceTransportName.usb]\n    )\n\n    func matches(device: VendorSpecificDeviceContext) -> Bool {\n        let maxInputReportSize = device.maxInputReportSize ?? 0\n        let maxOutputReportSize = device.maxOutputReportSize ?? 0\n\n        if isReceiverVendorChannel(device) {\n            return false\n        }\n\n        return matcher.matches(device: device)\n            && maxInputReportSize >= Constants.shortReportLength\n            && maxOutputReportSize >= Constants.shortReportLength\n    }\n\n    func metadata(for device: VendorSpecificDeviceContext) -> VendorSpecificDeviceMetadata? {\n        if let directTransport = directTransport(for: device) {\n            return metadata(using: directTransport)\n        }\n\n        if let receiverTransport = receiverTransport(for: device) {\n            return metadata(using: receiverTransport)\n        }\n\n        return nil\n    }\n\n    func receiverPointingDeviceDiscovery(for device: VendorSpecificDeviceContext) -> ReceiverPointingDeviceDiscovery {\n        guard device.transport == PointerDeviceTransportName.usb else {\n            os_log(\n                \"Skip receiver discovery for non-USB device: name=%{public}@ transport=%{public}@\",\n                log: Self.log,\n                type: .info,\n                device.name,\n                device.transport ?? \"(nil)\"\n            )\n            return .init(identities: [], connectionSnapshots: [:], liveReachableSlots: [])\n        }\n\n        guard let locationID = device.locationID else {\n            os_log(\n                \"Skip receiver discovery without locationID: name=%{public}@\",\n                log: Self.log,\n                type: .info,\n                device.name\n            )\n            return .init(identities: [], connectionSnapshots: [:], liveReachableSlots: [])\n        }\n\n        guard let receiverChannel = openReceiverChannel(for: device) else {\n            os_log(\n                \"Failed to open receiver channel: locationID=%{public}d name=%{public}@\",\n                log: Self.log,\n                type: .info,\n                locationID,\n                device.product ?? device.name\n            )\n            return .init(identities: [], connectionSnapshots: [:], liveReachableSlots: [])\n        }\n\n        let discovery = receiverPointingDeviceDiscovery(for: device, using: receiverChannel)\n        let slots = discovery.identities\n\n        let slotSummary = slots.map { identity in\n            let battery = identity.batteryLevel.map(String.init) ?? \"(nil)\"\n            let name = identity.name\n            return \"slot=\\(identity.slot) kind=\\(identity.kind.rawValue) name=\\(name) battery=\\(battery)\"\n        }\n        .joined(separator: \", \")\n\n        os_log(\n            \"Receiver discovery produced identities: locationID=%{public}d count=%{public}u identities=%{public}@\",\n            log: Self.log,\n            type: .info,\n            locationID,\n            UInt32(slots.count),\n            slotSummary\n        )\n\n        return discovery\n    }\n\n    func receiverPointingDeviceIdentities(for device: VendorSpecificDeviceContext) -> [ReceiverLogicalDeviceIdentity] {\n        receiverPointingDeviceDiscovery(for: device).identities\n    }\n\n    func openReceiverChannel(for device: VendorSpecificDeviceContext) -> LogitechReceiverChannel? {\n        guard device.transport == PointerDeviceTransportName.usb,\n              let locationID = device.locationID\n        else {\n            return nil\n        }\n\n        return LogitechReceiverChannel.open(locationID: locationID)\n    }\n\n    func receiverSlot(for device: VendorSpecificDeviceContext) -> UInt8? {\n        guard device.transport == PointerDeviceTransportName.usb,\n              let locationID = device.locationID,\n              let receiverChannel = LogitechReceiverChannel.open(locationID: locationID)\n        else {\n            return nil\n        }\n\n        return receiverSlot(for: device, using: receiverChannel)\n    }\n\n    func receiverSlot(for device: VendorSpecificDeviceContext, using receiver: LogitechReceiverChannel) -> UInt8? {\n        discoverReceiverSlot(for: device, using: receiver)?.slot\n    }\n\n    func receiverPointingDeviceDiscovery(\n        for device: VendorSpecificDeviceContext,\n        using receiverChannel: LogitechReceiverChannel\n    ) -> ReceiverPointingDeviceDiscovery {\n        receiverChannel.discoverPointingDeviceDiscovery(baseName: device.product ?? device.name)\n    }\n\n    func receiverSlotIdentity(\n        for device: VendorSpecificDeviceContext,\n        slot: UInt8,\n        connectionSnapshot: ReceiverConnectionSnapshot?,\n        using receiverChannel: LogitechReceiverChannel\n    ) -> ReceiverLogicalDeviceIdentity? {\n        guard let locationID = receiverChannel.locationID else {\n            return nil\n        }\n\n        guard let slotInfo = receiverChannel.discoverSlotInfo(slot, connectionSnapshot: connectionSnapshot) else {\n            return nil\n        }\n\n        guard let kind = ReceiverLogicalDeviceKind(rawValue: slotInfo.kind), kind.isPointingDevice else {\n            return nil\n        }\n\n        return ReceiverLogicalDeviceIdentity(\n            receiverLocationID: locationID,\n            slot: slot,\n            kind: kind,\n            name: slotInfo.name ?? device.product ?? device.name,\n            serialNumber: slotInfo.serialNumber,\n            productID: slotInfo.productID,\n            batteryLevel: slotInfo.batteryLevel\n        )\n    }\n\n    func waitForReceiverConnectionChange(\n        for device: VendorSpecificDeviceContext,\n        timeout: TimeInterval,\n        until shouldContinue: @escaping () -> Bool\n    ) -> [UInt8: ReceiverConnectionSnapshot] {\n        guard device.transport == PointerDeviceTransportName.usb,\n              let locationID = device.locationID,\n              let receiverChannel = LogitechReceiverChannel.open(locationID: locationID)\n        else {\n            os_log(\n                \"Skip receiver wait because channel is unavailable: name=%{public}@ transport=%{public}@ locationID=%{public}@\",\n                log: Self.log,\n                type: .info,\n                device.name,\n                device.transport ?? \"(nil)\",\n                device.locationID.map(String.init) ?? \"(nil)\"\n            )\n\n            let deadline = Date().addingTimeInterval(timeout)\n            while shouldContinue(), Date() < deadline {\n                CFRunLoopRunInMode(.defaultMode, 0.1, true)\n            }\n            return [:]\n        }\n\n        receiverChannel.enableWirelessNotifications()\n        return receiverChannel.waitForConnectionSnapshots(timeout: timeout, until: shouldContinue)\n    }\n\n    func waitForReceiverConnectionChange(\n        using receiverChannel: LogitechReceiverChannel,\n        timeout: TimeInterval,\n        until shouldContinue: @escaping () -> Bool\n    ) -> [UInt8: ReceiverConnectionSnapshot] {\n        receiverChannel.enableWirelessNotifications()\n        return receiverChannel.waitForConnectionSnapshots(timeout: timeout, until: shouldContinue)\n    }\n\n    private func metadata(using transport: LogitechHIDPPTransport) -> VendorSpecificDeviceMetadata? {\n        let name = readFriendlyName(using: transport) ?? readName(using: transport)\n        let batteryLevel = transport\n            .isReceiverRoutedDevice ? readReceiverBatteryLevel(using: transport) : readBatteryLevel(using: transport)\n\n        if name == nil, batteryLevel == nil {\n            return nil\n        }\n\n        return VendorSpecificDeviceMetadata(name: name, batteryLevel: batteryLevel)\n    }\n\n    private func directTransport(for device: VendorSpecificDeviceContext) -> LogitechHIDPPTransport? {\n        guard device.transport == PointerDeviceTransportName.bluetoothLowEnergy else {\n            return nil\n        }\n\n        return LogitechHIDPPTransport(device: device, deviceIndex: nil)\n    }\n\n    private func receiverTransport(for device: VendorSpecificDeviceContext) -> LogitechHIDPPTransport? {\n        guard device.transport == PointerDeviceTransportName.usb,\n              let locationID = device.locationID,\n              let receiverChannel = LogitechReceiverChannel.open(locationID: locationID),\n              let slot = discoverReceiverSlot(for: device, using: receiverChannel)?.slot\n        else {\n            return nil\n        }\n\n        return LogitechHIDPPTransport(device: receiverChannel, deviceIndex: slot)\n    }\n\n    private func discoverReceiverSlot(\n        for device: VendorSpecificDeviceContext,\n        using receiver: LogitechReceiverChannel\n    ) -> ReceiverSlotMatchCandidate? {\n        guard let discovery = receiver.discoverMatchCandidates(baseName: device.product ?? device.name) else {\n            return nil\n        }\n\n        let slots = discovery.0\n\n        let normalizedProduct = normalizeName(device.product ?? device.name)\n        let normalizedSerial = normalizeSerial(device.serialNumber)\n        let desiredProductID = device.productID\n\n        if let serialMatch = slots.first(where: {\n            normalizeSerial($0.serialNumber) == normalizedSerial && normalizedSerial != nil\n        }) {\n            return serialMatch\n        }\n\n        if let productIDMatch = slots.first(where: { candidate in\n            guard let desiredProductID, let productID = candidate.productID else {\n                return false\n            }\n\n            return productID == desiredProductID\n        }) {\n            return productIDMatch\n        }\n\n        if let exactNameMatch = slots.first(where: {\n            guard let name = $0.name else {\n                return false\n            }\n            return normalizeName(name) == normalizedProduct\n        }) {\n            return exactNameMatch\n        }\n\n        let desiredKinds = preferredReceiverDeviceKinds(for: device)\n        if let kindMatch = slots.first(where: { desiredKinds.contains($0.kind) }) {\n            return kindMatch\n        }\n\n        if slots.count == 1 {\n            return slots[0]\n        }\n\n        return nil\n    }\n\n    fileprivate func discoverRoutedSlots(using receiver: LogitechReceiverChannel) -> [ReceiverSlotMetadata] {\n        var results = [ReceiverSlotMetadata]()\n\n        for slot in UInt8(1) ... UInt8(6) {\n            guard let transport = LogitechHIDPPTransport(device: receiver, deviceIndex: slot) else {\n                continue\n            }\n\n            let name = readFriendlyName(using: transport) ?? readName(using: transport)\n            let batteryLevel = readReceiverBatteryLevel(using: transport)\n            guard name != nil || batteryLevel != nil else {\n                continue\n            }\n\n            results.append(.init(slot: slot, name: name, batteryLevel: batteryLevel))\n        }\n\n        return results\n    }\n\n    private func preferredReceiverDeviceKinds(for device: VendorSpecificDeviceContext) -> Set<UInt8> {\n        guard device.primaryUsagePage == kHIDPage_GenericDesktop else {\n            return []\n        }\n\n        switch device.primaryUsage {\n        case kHIDUsage_GD_Mouse, kHIDUsage_GD_Pointer:\n            return [DeviceKind.mouse.rawValue, DeviceKind.trackball.rawValue, DeviceKind.touchpad.rawValue]\n        default:\n            return []\n        }\n    }\n\n    fileprivate func readFriendlyName(using transport: LogitechHIDPPTransport) -> String? {\n        guard let featureIndex = transport.featureIndex(for: .deviceFriendlyName),\n              let lengthResponse = transport.request(featureIndex: featureIndex, function: 0x00, parameters: []),\n              let length = lengthResponse.payload.first,\n              length > 0\n        else {\n            return nil\n        }\n\n        return readNameFragments(\n            using: transport,\n            featureIndex: featureIndex,\n            length: Int(length),\n            skipFirstPayloadByte: true\n        )\n    }\n\n    fileprivate func readName(using transport: LogitechHIDPPTransport) -> String? {\n        guard let featureIndex = transport.featureIndex(for: .deviceName),\n              let lengthResponse = transport.request(featureIndex: featureIndex, function: 0x00, parameters: []),\n              let length = lengthResponse.payload.first,\n              length > 0\n        else {\n            return nil\n        }\n\n        return readNameFragments(\n            using: transport,\n            featureIndex: featureIndex,\n            length: Int(length),\n            skipFirstPayloadByte: false\n        )\n    }\n\n    private func readNameFragments(\n        using transport: LogitechHIDPPTransport,\n        featureIndex: UInt8,\n        length: Int,\n        skipFirstPayloadByte: Bool\n    ) -> String? {\n        var bytes = [UInt8]()\n        var offset = 0\n\n        while offset < length {\n            guard let response = transport.request(\n                featureIndex: featureIndex,\n                function: 0x01,\n                parameters: [UInt8(offset)]\n            ) else {\n                return nil\n            }\n\n            let fragment = skipFirstPayloadByte ? Array(response.payload.dropFirst()) : response.payload\n            if fragment.isEmpty {\n                break\n            }\n\n            bytes.append(contentsOf: fragment)\n            offset += fragment.count\n        }\n\n        guard !bytes.isEmpty else {\n            return nil\n        }\n\n        let trimmed = Array(bytes.prefix(length).prefix { $0 != 0 })\n        return String(bytes: trimmed.isEmpty ? Array(bytes.prefix(length)) : trimmed, encoding: .utf8)\n    }\n\n    fileprivate func readBatteryLevel(using transport: LogitechHIDPPTransport) -> Int? {\n        if let featureIndex = transport.featureIndex(for: .batteryStatus),\n           let response = transport.request(featureIndex: featureIndex, function: 0x00, parameters: []),\n           response.payload.count >= 3,\n           let level = response.payload.first,\n           (1 ... 100).contains(level) {\n            return Int(level)\n        }\n\n        if let featureIndex = transport.featureIndex(for: .unifiedBattery),\n           let response = transport.request(featureIndex: featureIndex, function: 0x00, parameters: []),\n           response.payload.count >= 2,\n           let status = transport.request(featureIndex: featureIndex, function: 0x01, parameters: []),\n           status.payload.count >= 4 {\n            let exactPercent = status.payload[0]\n            let supportsStateOfCharge = (response.payload[1] & 0x02) != 0\n            if supportsStateOfCharge, (1 ... 100).contains(exactPercent) {\n                return Int(exactPercent)\n            }\n\n            return ApproximateBatteryLevel(rawValue: status.payload[1])?.percent\n        }\n\n        if let featureIndex = transport.featureIndex(for: .batteryVoltage),\n           let response = transport.request(featureIndex: featureIndex, function: 0x00, parameters: []),\n           response.payload.count >= 2 {\n            return estimateBatteryPercent(fromMillivolts: Int(response.payload[0]) << 8 | Int(response.payload[1]))\n        }\n\n        if let featureIndex = transport.featureIndex(for: .adcMeasurement),\n           let response = transport.request(featureIndex: featureIndex, function: 0x00, parameters: []),\n           response.payload.count >= 2 {\n            return estimateBatteryPercent(fromMillivolts: Int(response.payload[0]) << 8 | Int(response.payload[1]))\n        }\n\n        return nil\n    }\n\n    fileprivate func readReceiverBatteryLevel(using transport: LogitechHIDPPTransport) -> Int? {\n        readBatteryLevel(using: transport)\n    }\n\n    private func estimateBatteryPercent(fromMillivolts millivolts: Int) -> Int {\n        let lowerBound = 3500\n        let upperBound = 4200\n        let clamped = max(lowerBound, min(upperBound, millivolts))\n        return Int(round(Double(clamped - lowerBound) / Double(upperBound - lowerBound) * 100))\n    }\n\n    private func isReceiverVendorChannel(_ device: VendorSpecificDeviceContext) -> Bool {\n        device.transport == PointerDeviceTransportName.usb\n            && device.primaryUsagePage == 0xFF00\n            && device.primaryUsage == 0x01\n    }\n\n    private func normalizeName(_ name: String) -> String {\n        name.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)\n    }\n\n    private func normalizeSerial(_ serialNumber: String?) -> String? {\n        guard let serialNumber, !serialNumber.isEmpty else {\n            return nil\n        }\n\n        return serialNumber.uppercased().replacingOccurrences(of: \":\", with: \"\")\n    }\n\n    static func parseReceiverConnectionNotification(\n        _ report: [UInt8]\n    ) -> (slot: UInt8, snapshot: ReceiverConnectionSnapshot)? {\n        guard report.count >= Constants.shortReportLength,\n              report[0] == Constants.shortReportID\n        else {\n            return nil\n        }\n\n        switch report[2] {\n        case 0x41:\n            let flags = report[4]\n            return (\n                slot: report[1],\n                snapshot: .init(isConnected: (flags & 0x40) == 0, kind: flags & 0x0F)\n            )\n        case 0x42:\n            return (\n                slot: report[1],\n                snapshot: .init(isConnected: (report[3] & 0x01) == 0, kind: nil)\n            )\n        default:\n            return nil\n        }\n    }\n\n    static func parseConnectedDeviceCount(_ response: [UInt8]) -> Int? {\n        guard response.count >= 6 else {\n            return nil\n        }\n\n        return Int(response[5])\n    }\n}\n\nstruct LogitechHIDPPTransport {\n    private let device: VendorSpecificDeviceContext\n    private let reportID: UInt8\n    private let reportLength: Int\n    private let deviceIndex: UInt8\n    private let acceptedReplyIndices: Set<UInt8>\n    let isReceiverRoutedDevice: Bool\n\n    init?(device: VendorSpecificDeviceContext, deviceIndex: UInt8?) {\n        let maxOutputReportSize = device.maxOutputReportSize ?? 0\n        if maxOutputReportSize >= LogitechHIDPPDeviceMetadataProvider.Constants.longReportLength {\n            reportID = LogitechHIDPPDeviceMetadataProvider.Constants.longReportID\n            reportLength = LogitechHIDPPDeviceMetadataProvider.Constants.longReportLength\n        } else if maxOutputReportSize >= LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength {\n            reportID = LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID\n            reportLength = LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength\n        } else {\n            return nil\n        }\n\n        self.device = device\n        self.deviceIndex = deviceIndex ?? LogitechHIDPPDeviceMetadataProvider.Constants.receiverIndex\n        isReceiverRoutedDevice = deviceIndex != nil\n        acceptedReplyIndices = deviceIndex.map { Set([$0]) } ?? LogitechHIDPPDeviceMetadataProvider.Constants\n            .directReplyIndices\n    }\n\n    func featureIndex(for featureID: LogitechHIDPPDeviceMetadataProvider.FeatureID) -> UInt8? {\n        guard let response = request(featureIndex: 0x00, function: 0x00, parameters: featureID.bytes),\n              let featureIndex = response.payload.first,\n              featureIndex != 0\n        else {\n            return nil\n        }\n\n        return featureIndex\n    }\n\n    func request(featureIndex: UInt8, function: UInt8, parameters: [UInt8]) -> LogitechHIDPPDeviceMetadataProvider\n        .Response? {\n        let address = (function << 4) | LogitechHIDPPDeviceMetadataProvider.Constants.softwareID\n        var bytes = [UInt8](repeating: 0, count: reportLength)\n        bytes[0] = reportID\n        bytes[1] = deviceIndex\n        bytes[2] = featureIndex\n        bytes[3] = address\n        for (index, parameter) in parameters.enumerated() where index + 4 < bytes.count {\n            bytes[index + 4] = parameter\n        }\n\n        guard let response = device.performSynchronousOutputReportRequest(\n            Data(bytes),\n            timeout: LogitechHIDPPDeviceMetadataProvider.Constants.timeout,\n            matching: { response in\n                let reply = [UInt8](response)\n                guard reply.count >= LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength,\n                      [LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID,\n                       LogitechHIDPPDeviceMetadataProvider.Constants.longReportID].contains(reply[0]),\n                      acceptedReplyIndices.contains(reply[1])\n                else {\n                    return false\n                }\n\n                if reply[2] == 0xFF {\n                    return reply.count >= 6 && reply[3] == featureIndex && reply[4] == address\n                }\n\n                return reply[2] == featureIndex && reply[3] == address\n            }\n        ) else {\n            return nil\n        }\n\n        let reply = [UInt8](response)\n        guard reply.count >= 4, reply[2] != 0xFF else {\n            return nil\n        }\n\n        return .init(payload: Array(reply.dropFirst(4)))\n    }\n}\n\nfinal class LogitechReceiverChannel: VendorSpecificDeviceContext {\n    private enum RequestStrategy: CaseIterable {\n        case outputCallback\n        case featureCallback\n        case outputFeatureGet\n        case featureFeatureGet\n        case outputInputGet\n        case featureInputGet\n\n        var requestType: IOHIDReportType {\n            switch self {\n            case .outputCallback, .outputFeatureGet, .outputInputGet:\n                return kIOHIDReportTypeOutput\n            case .featureCallback, .featureFeatureGet, .featureInputGet:\n                return kIOHIDReportTypeFeature\n            }\n        }\n\n        var responseType: IOHIDReportType? {\n            switch self {\n            case .outputCallback, .featureCallback:\n                return nil\n            case .outputFeatureGet, .featureFeatureGet:\n                return kIOHIDReportTypeFeature\n            case .outputInputGet, .featureInputGet:\n                return kIOHIDReportTypeInput\n            }\n        }\n    }\n\n    let vendorID: Int?\n    let productID: Int?\n    let product: String?\n    let name: String\n    let serialNumber: String?\n    let transport: String?\n    let locationID: Int?\n    let primaryUsagePage: Int?\n    let primaryUsage: Int?\n    let maxInputReportSize: Int?\n    let maxOutputReportSize: Int?\n    let maxFeatureReportSize: Int?\n\n    private let manager: IOHIDManager\n    private let device: IOHIDDevice\n    private var inputReportBuffer: UnsafeMutablePointer<UInt8>?\n    private let pendingLock = NSLock()\n    private let requestLock = NSLock()\n    private let strategyLock = NSLock()\n    private var pendingMatcher: ((Data) -> Bool)?\n    private var pendingResponse: Data?\n    private var pendingSemaphore: DispatchSemaphore?\n    private var requestStrategy: RequestStrategy?\n\n    private static let inputReportCallback: IOHIDReportCallback = { context, _, _, _, _, report, reportLength in\n        guard let context else {\n            return\n        }\n\n        let this = Unmanaged<LogitechReceiverChannel>.fromOpaque(context).takeUnretainedValue()\n        this.handleInputReport(Data(bytes: report, count: reportLength))\n    }\n\n    static func open(locationID: Int) -> LogitechReceiverChannel? {\n        let manager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))\n\n        let matching: [String: Any] = [\n            kIOHIDVendorIDKey: LogitechHIDPPDeviceMetadataProvider.Constants.vendorID,\n            \"LocationID\": locationID,\n            \"Transport\": PointerDeviceTransportName.usb,\n            kIOHIDPrimaryUsagePageKey: 0xFF00,\n            kIOHIDPrimaryUsageKey: 0x01\n        ]\n\n        IOHIDManagerSetDeviceMatching(manager, matching as CFDictionary)\n        IOHIDManagerScheduleWithRunLoop(manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n        IOHIDManagerOpen(manager, IOOptionBits(kIOHIDOptionsTypeNone))\n\n        guard let devices = IOHIDManagerCopyDevices(manager) as? Set<IOHIDDevice>,\n              let hidDevice = devices.first\n        else {\n            IOHIDManagerUnscheduleFromRunLoop(manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n            IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone))\n            return nil\n        }\n\n        return LogitechReceiverChannel(manager: manager, device: hidDevice)\n    }\n\n    init?(manager: IOHIDManager, device: IOHIDDevice) {\n        self.manager = manager\n        self.device = device\n        vendorID = Self.getProperty(kIOHIDVendorIDKey, from: device)\n        productID = Self.getProperty(kIOHIDProductIDKey, from: device)\n        product = Self.getProperty(kIOHIDProductKey, from: device)\n        name = product ?? \"(unknown)\"\n        serialNumber = Self.getProperty(kIOHIDSerialNumberKey, from: device)\n        transport = Self.getProperty(\"Transport\", from: device)\n        locationID = Self.getProperty(\"LocationID\", from: device)\n        primaryUsagePage = Self.getProperty(kIOHIDPrimaryUsagePageKey, from: device)\n        primaryUsage = Self.getProperty(kIOHIDPrimaryUsageKey, from: device)\n        maxInputReportSize = Self.getProperty(\"MaxInputReportSize\", from: device)\n        maxOutputReportSize = Self.getProperty(\"MaxOutputReportSize\", from: device)\n        maxFeatureReportSize = Self.getProperty(\"MaxFeatureReportSize\", from: device)\n\n        let openStatus = IOHIDDeviceOpen(device, IOOptionBits(kIOHIDOptionsTypeNone))\n        guard openStatus == kIOReturnSuccess else {\n            IOHIDManagerUnscheduleFromRunLoop(manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n            IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone))\n            return nil\n        }\n\n        let reportLength = max(\n            maxInputReportSize ?? LogitechHIDPPDeviceMetadataProvider.Constants.longReportLength,\n            LogitechHIDPPDeviceMetadataProvider.Constants.longReportLength\n        )\n        inputReportBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: reportLength)\n        guard let inputReportBuffer else {\n            IOHIDDeviceClose(device, IOOptionBits(kIOHIDOptionsTypeNone))\n            IOHIDManagerUnscheduleFromRunLoop(manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n            IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone))\n            return nil\n        }\n\n        IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n        IOHIDDeviceRegisterInputReportCallback(\n            device,\n            inputReportBuffer,\n            reportLength,\n            Self.inputReportCallback,\n            Unmanaged.passUnretained(self).toOpaque()\n        )\n    }\n\n    deinit {\n        inputReportBuffer?.deallocate()\n        IOHIDDeviceUnscheduleFromRunLoop(device, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n        IOHIDDeviceClose(device, IOOptionBits(kIOHIDOptionsTypeNone))\n        IOHIDManagerUnscheduleFromRunLoop(manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n        IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone))\n    }\n\n    func discoverSlots() -> LogitechHIDPPDeviceMetadataProvider.ReceiverSlotDiscovery? {\n        let connectedDeviceCount = readConnectionState().flatMap { response in\n            LogitechHIDPPDeviceMetadataProvider.parseConnectedDeviceCount(response)\n        }\n        let connectionSnapshots = discoverConnectionSnapshots(expectedCount: connectedDeviceCount)\n        let snapshotSummary = connectionSnapshots.keys\n            .sorted()\n            .compactMap { slot -> String? in\n                guard let snapshot = connectionSnapshots[slot] else {\n                    return nil\n                }\n\n                let kind = snapshot.kind.map(String.init) ?? \"(nil)\"\n                return \"slot=\\(slot) connected=\\(snapshot.isConnected) kind=\\(kind)\"\n            }\n            .joined(separator: \", \")\n\n        os_log(\n            \"Receiver slot discovery started: locationID=%{public}@ connectedCount=%{public}@ snapshots=%{public}@\",\n            log: LogitechHIDPPDeviceMetadataProvider.log,\n            type: .info,\n            locationID.map(String.init) ?? \"(nil)\",\n            connectedDeviceCount.map(String.init) ?? \"(nil)\",\n            snapshotSummary\n        )\n\n        // Prioritize slots known to be connected, then scan remaining slots\n        let connectedSlotNumbers = connectionSnapshots\n            .filter(\\.value.isConnected)\n            .map(\\.key)\n            .sorted()\n        let remainingSlots = (UInt8(1) ... UInt8(6)).filter { !connectedSlotNumbers.contains($0) }\n        let orderedSlots = connectedSlotNumbers + remainingSlots\n\n        var pairedSlots = [LogitechHIDPPDeviceMetadataProvider.ReceiverSlotInfo]()\n        for slot in orderedSlots {\n            guard let slotInfo = discoverSlotInfo(slot, connectionSnapshot: connectionSnapshots[slot]) else {\n                continue\n            }\n\n            pairedSlots.append(slotInfo)\n\n            os_log(\n                \"Receiver slot %u raw candidate: name=%{public}@ kind=%{public}u battery=%{public}@\",\n                log: LogitechHIDPPDeviceMetadataProvider.log,\n                type: .info,\n                slot,\n                slotInfo.name ?? \"(nil)\",\n                UInt32(slotInfo.kind),\n                slotInfo.batteryLevel.map(String.init) ?? \"(nil)\"\n            )\n        }\n\n        let pairedSummary = pairedSlots.map { slot in\n            let battery = slot.batteryLevel.map(String.init) ?? \"(nil)\"\n            let name = slot.name ?? \"(nil)\"\n            return \"slot=\\(slot.slot) kind=\\(slot.kind) name=\\(name) battery=\\(battery)\"\n        }\n        .joined(separator: \", \")\n\n        os_log(\n            \"Receiver slot metadata discovered: locationID=%{public}@ paired=%{public}u slots=%{public}@\",\n            log: LogitechHIDPPDeviceMetadataProvider.log,\n            type: .info,\n            locationID.map(String.init) ?? \"(nil)\",\n            UInt32(pairedSlots.count),\n            pairedSummary\n        )\n\n        return pairedSlots.isEmpty ? nil : .init(slots: pairedSlots, connectionSnapshots: connectionSnapshots)\n    }\n\n    func discoverSlotInfo(\n        _ slot: UInt8,\n        connectionSnapshot: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot? = nil\n    ) -> LogitechHIDPPDeviceMetadataProvider.ReceiverSlotInfo? {\n        let metadataProvider = LogitechHIDPPDeviceMetadataProvider()\n        let pairingResponse = hidpp10LongRequest(\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverInfoRegister,\n            subregister: UInt8(0x20 + Int(slot) - 1)\n        )\n        let extendedPairingResponse = hidpp10LongRequest(\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverInfoRegister,\n            subregister: UInt8(0x30 + Int(slot) - 1)\n        )\n        let nameResponse = hidpp10LongRequest(\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverInfoRegister,\n            subregister: UInt8(0x40 + Int(slot) - 1)\n        )\n\n        guard pairingResponse != nil || nameResponse != nil else {\n            return nil\n        }\n\n        let kind = connectionSnapshot?.kind\n            ?? pairingResponse.flatMap(Self.parseReceiverKind)\n            ?? 0\n        let routedTransport = LogitechHIDPPTransport(device: self, deviceIndex: slot)\n        let routedName = routedTransport.flatMap { transport in\n            metadataProvider.readFriendlyName(using: transport) ?? metadataProvider.readName(using: transport)\n        }\n        let batteryLevel = routedTransport.flatMap {\n            metadataProvider.readReceiverBatteryLevel(using: $0)\n        }\n        let name = nameResponse.flatMap(Self.parseReceiverName) ?? routedName\n        let productID = pairingResponse.flatMap(Self.parseReceiverProductID)\n        let serialNumber = extendedPairingResponse.flatMap(Self.parseReceiverSerialNumber)\n\n        return .init(\n            slot: slot,\n            kind: kind,\n            name: name,\n            productID: productID,\n            serialNumber: serialNumber,\n            batteryLevel: batteryLevel,\n            hasLiveMetadata: routedName != nil || batteryLevel != nil\n        )\n    }\n\n    private func discoverConnectionSnapshots(\n        expectedCount: Int? = nil\n    ) -> [UInt8: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot] {\n        guard triggerConnectionNotifications() else {\n            return [:]\n        }\n\n        var snapshots = [UInt8: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot]()\n        let deadline = Date().addingTimeInterval(0.5)\n        while Date() < deadline {\n            guard let report = waitForInputReport(timeout: 0.05, matching: { response in\n                LogitechHIDPPDeviceMetadataProvider.parseReceiverConnectionNotification(Array(response)) != nil\n            }) else {\n                // No more notifications pending — if we already have enough connected snapshots, exit early\n                if let expectedCount,\n                   snapshots.values.filter(\\.isConnected).count >= expectedCount {\n                    break\n                }\n                continue\n            }\n\n            guard let notification = LogitechHIDPPDeviceMetadataProvider\n                .parseReceiverConnectionNotification(Array(report)) else {\n                continue\n            }\n\n            snapshots[notification.slot] = notification.snapshot\n\n            // Exit early once we have all expected connected device snapshots\n            if let expectedCount,\n               snapshots.values.filter(\\.isConnected).count >= expectedCount {\n                break\n            }\n        }\n\n        return snapshots\n    }\n\n    func discoverMatchCandidates(baseName: String)\n        -> (\n            [LogitechHIDPPDeviceMetadataProvider.ReceiverSlotMatchCandidate],\n            [UInt8: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot]\n        )? {\n        enableWirelessNotifications()\n\n        guard let discovery = discoverSlots() else {\n            return nil\n        }\n\n        let slots = discovery.slots\n\n        let provider = LogitechHIDPPDeviceMetadataProvider()\n        let candidates = slots.map { slot in\n            LogitechHIDPPDeviceMetadataProvider.ReceiverSlotMatchCandidate(\n                slot: slot.slot,\n                kind: slot.kind,\n                name: slot.name ?? baseName,\n                serialNumber: slot.serialNumber,\n                productID: slot.productID,\n                batteryLevel: slot.batteryLevel ?? LogitechHIDPPTransport(device: self, deviceIndex: slot.slot)\n                    .flatMap { provider.readReceiverBatteryLevel(using: $0) },\n                hasLiveMetadata: slot.hasLiveMetadata\n            )\n        }\n\n        guard !candidates.isEmpty else {\n            return nil\n        }\n\n        return (candidates, discovery.connectionSnapshots)\n    }\n\n    func enableWirelessNotifications() {\n        let currentFlags = readNotificationFlags() ?? 0\n        let desiredFlags = currentFlags | LogitechHIDPPDeviceMetadataProvider.Constants.receiverWirelessNotifications\n            | LogitechHIDPPDeviceMetadataProvider.Constants.receiverSoftwarePresentNotifications\n        if desiredFlags != currentFlags {\n            _ = writeNotificationFlags(desiredFlags)\n        }\n    }\n\n    func discoverPointingDeviceDiscovery(baseName: String) -> LogitechHIDPPDeviceMetadataProvider\n        .ReceiverPointingDeviceDiscovery {\n        guard let locationID,\n              let discovery = discoverMatchCandidates(baseName: baseName)\n        else {\n            return .init(identities: [], connectionSnapshots: [:], liveReachableSlots: [])\n        }\n\n        let (slots, connectionSnapshots) = discovery\n        let liveReachableSlots = Set(slots.compactMap { slot in\n            slot.hasLiveMetadata ? slot.slot : nil\n        })\n\n        let identities = slots.compactMap { slot -> ReceiverLogicalDeviceIdentity? in\n            guard let kind = ReceiverLogicalDeviceKind(rawValue: slot.kind), kind.isPointingDevice else {\n                return nil\n            }\n\n            return ReceiverLogicalDeviceIdentity(\n                receiverLocationID: locationID,\n                slot: slot.slot,\n                kind: kind,\n                name: slot.name ?? baseName,\n                serialNumber: slot.serialNumber,\n                productID: slot.productID,\n                batteryLevel: slot.batteryLevel\n            )\n        }\n\n        return .init(\n            identities: identities,\n            connectionSnapshots: connectionSnapshots,\n            liveReachableSlots: liveReachableSlots\n        )\n    }\n\n    func waitForConnectionSnapshots(\n        timeout: TimeInterval,\n        until shouldContinue: (() -> Bool)? = nil\n    ) -> [UInt8: LogitechHIDPPDeviceMetadataProvider.ReceiverConnectionSnapshot] {\n        guard let report = waitForInputReport(\n            timeout: timeout,\n            matching: { response in\n                LogitechHIDPPDeviceMetadataProvider.parseReceiverConnectionNotification(Array(response)) != nil\n            },\n            until: shouldContinue\n        ),\n            let initialNotification = LogitechHIDPPDeviceMetadataProvider\n            .parseReceiverConnectionNotification(Array(report))\n        else {\n            return [:]\n        }\n\n        var snapshots = [initialNotification.slot: initialNotification.snapshot]\n        let deadline = Date().addingTimeInterval(0.1)\n        while Date() < deadline {\n            guard let followup = waitForInputReport(\n                timeout: 0.02,\n                matching: { response in\n                    LogitechHIDPPDeviceMetadataProvider.parseReceiverConnectionNotification(Array(response)) != nil\n                },\n                until: shouldContinue\n            ),\n                let notification = LogitechHIDPPDeviceMetadataProvider\n                .parseReceiverConnectionNotification(Array(followup))\n            else {\n                continue\n            }\n\n            snapshots[notification.slot] = notification.snapshot\n        }\n\n        return snapshots\n    }\n\n    func waitForHIDPPNotification(\n        timeout: TimeInterval,\n        matching: @escaping ([UInt8]) -> Bool,\n        until shouldContinue: (() -> Bool)? = nil\n    ) -> [UInt8]? {\n        waitForInputReport(\n            timeout: timeout,\n            matching: { matching(Array($0)) },\n            until: shouldContinue\n        )\n        .map(Array.init)\n    }\n\n    func readNotificationFlags() -> UInt32? {\n        guard let response = hidpp10ShortRequest(\n            subID: 0x81,\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverNotificationFlagsRegister,\n            parameters: [0, 0, 0]\n        ) else {\n            return nil\n        }\n\n        return UInt32(response[4]) << 16 | UInt32(response[5]) << 8 | UInt32(response[6])\n    }\n\n    func writeNotificationFlags(_ value: UInt32) -> Bool {\n        hidpp10ShortRequest(\n            subID: 0x80,\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverNotificationFlagsRegister,\n            parameters: [UInt8((value >> 16) & 0xFF), UInt8((value >> 8) & 0xFF), UInt8(value & 0xFF)]\n        ) != nil\n    }\n\n    func performSynchronousOutputReportRequest(\n        _ report: Data,\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool\n    ) -> Data? {\n        if let strategy = currentRequestStrategy(),\n           let response = performRequest(report, timeout: timeout, matching: matching, strategy: strategy) {\n            return response\n        }\n\n        for strategy in RequestStrategy.allCases {\n            guard let response = performRequest(report, timeout: timeout, matching: matching, strategy: strategy) else {\n                continue\n            }\n\n            setCurrentRequestStrategy(strategy)\n            return response\n        }\n\n        clearCurrentRequestStrategy()\n        return nil\n    }\n\n    private func performRequest(\n        _ report: Data,\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool,\n        strategy: RequestStrategy\n    ) -> Data? {\n        guard !report.isEmpty else {\n            return nil\n        }\n\n        if let responseType = strategy.responseType {\n            return performGetReportRequest(\n                report,\n                timeout: timeout,\n                matching: matching,\n                requestType: strategy.requestType,\n                responseType: responseType\n            )\n        }\n\n        return performCallbackRequest(report, timeout: timeout, matching: matching, reportType: strategy.requestType)\n    }\n\n    private func performCallbackRequest(\n        _ report: Data,\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool,\n        reportType: IOHIDReportType\n    ) -> Data? {\n        requestLock.lock()\n        defer { requestLock.unlock() }\n\n        let semaphore = DispatchSemaphore(value: 0)\n        pendingLock.lock()\n        pendingMatcher = matching\n        pendingResponse = nil\n        pendingSemaphore = semaphore\n        pendingLock.unlock()\n\n        let status = sendReport(report, type: reportType)\n        guard status == kIOReturnSuccess else {\n            clearPendingRequest()\n            return nil\n        }\n\n        return waitForPendingResponse(timeout: timeout)\n    }\n\n    private func performGetReportRequest(\n        _ report: Data,\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool,\n        requestType: IOHIDReportType,\n        responseType: IOHIDReportType\n    ) -> Data? {\n        requestLock.lock()\n        defer { requestLock.unlock() }\n\n        clearPendingRequest()\n        guard sendReport(report, type: requestType) == kIOReturnSuccess else {\n            return nil\n        }\n\n        let deadline = Date().addingTimeInterval(timeout)\n        while Date() < deadline {\n            if let response = getMatchingReport(type: responseType, matching: matching) {\n                return response\n            }\n\n            CFRunLoopRunInMode(.defaultMode, 0.01, true)\n        }\n\n        return nil\n    }\n\n    private func sendReport(_ report: Data, type: IOHIDReportType) -> IOReturn {\n        report.withUnsafeBytes { rawBuffer -> IOReturn in\n            guard let baseAddress = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {\n                return kIOReturnBadArgument\n            }\n\n            return IOHIDDeviceSetReport(device, type, CFIndex(report[0]), baseAddress, report.count)\n        }\n    }\n\n    private func getMatchingReport(type: IOHIDReportType, matching: @escaping (Data) -> Bool) -> Data? {\n        for candidate in candidateReportDescriptors() {\n            guard let response = getReport(type: type, reportID: candidate.reportID, length: candidate.length),\n                  matching(response) else {\n                continue\n            }\n\n            return response\n        }\n\n        return nil\n    }\n\n    private func getReport(type: IOHIDReportType, reportID: UInt8, length: Int) -> Data? {\n        guard length >= LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength else {\n            return nil\n        }\n\n        var buffer = [UInt8](repeating: 0, count: length)\n        buffer[0] = reportID\n        var reportLength = CFIndex(length)\n\n        let status = buffer.withUnsafeMutableBytes { rawBuffer -> IOReturn in\n            guard let baseAddress = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {\n                return kIOReturnBadArgument\n            }\n\n            return IOHIDDeviceGetReport(device, type, CFIndex(reportID), baseAddress, &reportLength)\n        }\n\n        guard status == kIOReturnSuccess,\n              reportLength >= LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength else {\n            return nil\n        }\n\n        return Data(buffer.prefix(reportLength))\n    }\n\n    private func candidateReportDescriptors() -> [(reportID: UInt8, length: Int)] {\n        var descriptors = [(UInt8, Int)]()\n\n        let shortLength = max(\n            LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength,\n            max(maxInputReportSize ?? 0, maxFeatureReportSize ?? 0)\n        )\n        descriptors.append((LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID, shortLength))\n\n        let longLength = max(\n            LogitechHIDPPDeviceMetadataProvider.Constants.longReportLength,\n            max(maxInputReportSize ?? 0, maxFeatureReportSize ?? 0)\n        )\n        descriptors.append((LogitechHIDPPDeviceMetadataProvider.Constants.longReportID, longLength))\n\n        return descriptors\n    }\n\n    private func currentRequestStrategy() -> RequestStrategy? {\n        strategyLock.lock()\n        defer { strategyLock.unlock() }\n        return requestStrategy\n    }\n\n    private func setCurrentRequestStrategy(_ strategy: RequestStrategy) {\n        strategyLock.lock()\n        requestStrategy = strategy\n        strategyLock.unlock()\n    }\n\n    private func clearCurrentRequestStrategy() {\n        strategyLock.lock()\n        requestStrategy = nil\n        strategyLock.unlock()\n    }\n\n    private func waitForInputReport(\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool,\n        until shouldContinue: (() -> Bool)? = nil\n    ) -> Data? {\n        requestLock.lock()\n        defer { requestLock.unlock() }\n\n        let semaphore = DispatchSemaphore(value: 0)\n        pendingLock.lock()\n        pendingMatcher = matching\n        pendingResponse = nil\n        pendingSemaphore = semaphore\n        pendingLock.unlock()\n\n        return waitForPendingResponse(timeout: timeout, until: shouldContinue)\n    }\n\n    private func waitForPendingResponse(timeout: TimeInterval, until shouldContinue: (() -> Bool)? = nil) -> Data? {\n        let deadline = Date().addingTimeInterval(timeout)\n        while Date() < deadline {\n            if let shouldContinue, !shouldContinue() {\n                clearPendingRequest()\n                return nil\n            }\n\n            pendingLock.lock()\n            let response = pendingResponse\n            pendingLock.unlock()\n\n            if let response {\n                clearPendingRequest()\n                return response\n            }\n\n            CFRunLoopRunInMode(.defaultMode, 0.01, true)\n        }\n\n        clearPendingRequest()\n        return nil\n    }\n\n    private func handleInputReport(_ report: Data) {\n        pendingLock.lock()\n        defer { pendingLock.unlock() }\n\n        guard let reportMatcher = pendingMatcher, reportMatcher(report) else {\n            return\n        }\n\n        pendingResponse = report\n        pendingMatcher = nil\n        pendingSemaphore?.signal()\n    }\n\n    private func clearPendingRequest() {\n        pendingLock.lock()\n        pendingMatcher = nil\n        pendingResponse = nil\n        pendingSemaphore = nil\n        pendingLock.unlock()\n    }\n\n    private func readConnectionState() -> [UInt8]? {\n        hidpp10ShortRequest(\n            subID: 0x81,\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverConnectionStateRegister,\n            parameters: [0, 0, 0]\n        )\n    }\n\n    private func triggerConnectionNotifications() -> Bool {\n        hidpp10ShortRequest(\n            subID: 0x80,\n            register: LogitechHIDPPDeviceMetadataProvider.Constants.receiverConnectionStateRegister,\n            parameters: [0x02, 0x00, 0x00]\n        ) != nil\n    }\n\n    private func hidpp10ShortRequest(subID: UInt8, register: UInt8, parameters: [UInt8]) -> [UInt8]? {\n        var bytes = [UInt8](repeating: 0, count: LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength)\n        bytes[0] = LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID\n        bytes[1] = LogitechHIDPPDeviceMetadataProvider.Constants.receiverIndex\n        bytes[2] = subID\n        bytes[3] = register\n        for (index, parameter) in parameters.prefix(3).enumerated() {\n            bytes[4 + index] = parameter\n        }\n\n        let response = performSynchronousOutputReportRequest(\n            Data(bytes),\n            timeout: LogitechHIDPPDeviceMetadataProvider.Constants.timeout\n        ) { report in\n            let reply = [UInt8](report)\n            guard reply.count >= LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength else {\n                return false\n            }\n\n            guard [\n                LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID,\n                LogitechHIDPPDeviceMetadataProvider.Constants.longReportID\n            ].contains(reply[0]), reply[1] == LogitechHIDPPDeviceMetadataProvider.Constants.receiverIndex else {\n                return false\n            }\n\n            if reply[2] == 0x8F {\n                return reply[3] == subID && reply[4] == register\n            }\n\n            return reply[2] == subID\n                && reply[3] == register\n        }\n\n        guard let response else {\n            return nil\n        }\n\n        let responseBytes = Array(response)\n        return responseBytes[2] == 0x8F ? nil : responseBytes\n    }\n\n    private func hidpp10LongRequest(register: UInt8, subregister: UInt8) -> [UInt8]? {\n        var bytes = [UInt8](repeating: 0, count: LogitechHIDPPDeviceMetadataProvider.Constants.shortReportLength)\n        bytes[0] = LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID\n        bytes[1] = LogitechHIDPPDeviceMetadataProvider.Constants.receiverIndex\n        bytes[2] = 0x83\n        bytes[3] = register\n        bytes[4] = subregister\n\n        let request = Data(bytes)\n\n        let response = performSynchronousOutputReportRequest(\n            request,\n            timeout: LogitechHIDPPDeviceMetadataProvider.Constants.timeout\n        ) { report in\n            let reply = [UInt8](report)\n            guard reply.count >= 5 else {\n                return false\n            }\n\n            guard [\n                LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID,\n                LogitechHIDPPDeviceMetadataProvider.Constants.longReportID\n            ].contains(reply[0]), reply[1] == LogitechHIDPPDeviceMetadataProvider.Constants.receiverIndex else {\n                return false\n            }\n\n            if reply[2] == 0x8F {\n                return reply[3] == 0x83 && reply[4] == register\n            }\n\n            return reply[2] == 0x83\n                && reply[3] == register\n                && reply[4] == subregister\n        }\n\n        guard let response else {\n            return nil\n        }\n\n        let responseBytes = Array(response)\n        return responseBytes[2] == 0x8F ? nil : responseBytes\n    }\n\n    private static func parseReceiverName(_ response: [UInt8]) -> String? {\n        guard response.count >= 6 else {\n            return nil\n        }\n\n        let length = Int(response[5])\n        let bytes = Array(response.dropFirst(6).prefix(length))\n        return String(bytes: bytes, encoding: .utf8)\n    }\n\n    private static func parseReceiverKind(_ response: [UInt8]) -> UInt8? {\n        guard response.count >= 13 else {\n            return nil\n        }\n\n        let candidateIndices = [11, 12]\n        for index in candidateIndices where index < response.count {\n            let kind = response[index] & 0x0F\n            if kind != 0 {\n                return kind\n            }\n        }\n\n        return nil\n    }\n\n    private static func parseReceiverProductID(_ response: [UInt8]) -> Int? {\n        guard response.count >= 9 else {\n            return nil\n        }\n\n        return Int(response[7]) << 8 | Int(response[8])\n    }\n\n    private static func parseReceiverSerialNumber(_ response: [UInt8]) -> String? {\n        guard response.count >= 10 else {\n            return nil\n        }\n\n        return response[6 ... 9].map { String(format: \"%02X\", $0) }.joined()\n    }\n\n    private static func getProperty<T>(_ key: String, from device: IOHIDDevice) -> T? {\n        guard let value = IOHIDDeviceGetProperty(device, key as CFString) else {\n            return nil\n        }\n\n        return value as? T\n    }\n}\n\nprivate extension LogitechHIDPPDeviceMetadataProvider.FeatureID {\n    var bytes: [UInt8] {\n        [UInt8(rawValue >> 8), UInt8(rawValue & 0xFF)]\n    }\n}\n\nfinal class LogitechReprogrammableControlsMonitor {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"LogitechReprogrammableControls\")\n\n    private enum Constants {\n        static let notificationTimeout: TimeInterval = 0.25\n        static let stopTimeout: TimeInterval = 3\n    }\n\n    private struct ControlInfo {\n        let controlID: UInt16\n        let taskID: UInt16\n        let position: UInt8\n        let group: UInt8\n        let groupMask: UInt8\n        let flags: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.ControlFlags\n    }\n\n    private struct ReportingInfo {\n        let flags: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.ReportingFlags\n        let mappedControlID: UInt16\n    }\n\n    struct TargetDevice {\n        let slot: UInt8\n        let identity: ReceiverLogicalDeviceIdentity?\n    }\n\n    private struct MonitorTarget {\n        let slot: UInt8\n        let identity: ReceiverLogicalDeviceIdentity?\n        let transport: LogitechHIDPPTransport\n        let featureIndex: UInt8\n        let controls: [ControlInfo]\n        let notificationEndpoint: HIDPPNotificationHandling\n    }\n\n    private let device: Device\n    private let provider = LogitechHIDPPDeviceMetadataProvider()\n    private let stateLock = NSLock()\n    private var subscriptions = Set<AnyCancellable>()\n    private var directDeviceReportObservationToken: ObservationToken?\n\n    private var workerThread: Thread?\n    private var running = false\n    private var pressedButtons = Set<Int>()\n    private var needsReconfiguration = false\n    private var needsForcedReconfiguration = false\n\n    init(device: Device) {\n        self.device = device\n    }\n\n    static func supports(device: Device) -> Bool {\n        guard let vendorID = device.vendorID,\n              vendorID == LogitechHIDPPDeviceMetadataProvider.Constants.vendorID,\n              [PointerDeviceTransportName.usb, PointerDeviceTransportName.bluetoothLowEnergy]\n              .contains(device.pointerDevice.transport)\n        else {\n            return false\n        }\n\n        return true\n    }\n\n    func start() {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n\n        guard !running else {\n            return\n        }\n\n        running = true\n        let thread = Thread { [weak self] in\n            self?.workerMain()\n        }\n        thread.name = \"linearmouse.logitech-controls.\\(device.id)\"\n        workerThread = thread\n        thread.start()\n\n        observeConfigurationChangesIfNeeded()\n    }\n\n    func stop() {\n        stateLock.lock()\n        running = false\n        let thread = workerThread\n        workerThread = nil\n        stateLock.unlock()\n\n        thread?.cancel()\n        subscriptions.removeAll()\n        directDeviceReportObservationToken = nil\n    }\n\n    private func workerMain() {\n        defer {\n            releaseButtonIfNeeded()\n        }\n\n        guard let monitorTarget = resolveMonitorTarget() else {\n            finishVirtualButtonRecordingPreparationIfNeeded(sessionID: SettingsState.shared\n                .virtualButtonRecordingSessionID)\n            os_log(\n                \"Skip Logitech controls monitor because initialization failed: device=%{public}@\",\n                log: Self.log,\n                type: .info,\n                String(describing: device)\n            )\n            return\n        }\n\n        let locationID = device.pointerDevice.locationID ?? 0\n        let slot = monitorTarget.slot\n        let transport = monitorTarget.transport\n        let featureIndex = monitorTarget.featureIndex\n        let allControls = monitorTarget.controls\n        let targetIdentity = monitorTarget.identity\n        let targetName = targetIdentity?.name ?? device.productName ?? device.name\n        var pendingReportingRestoreByControlID = [UInt16: ReportingInfo]()\n\n        monitorTarget.notificationEndpoint.enableNotifications()\n        logAvailableControls(transport: transport, featureIndex: featureIndex, slot: slot, locationID: locationID)\n\n        while shouldContinueRunning() {\n            if !pendingReportingRestoreByControlID.isEmpty {\n                pendingReportingRestoreByControlID = restoreReportingState(\n                    pendingReportingRestoreByControlID,\n                    using: transport,\n                    featureIndex: featureIndex,\n                    locationID: locationID,\n                    slot: slot,\n                    reason: \"retry pending restore\"\n                )\n            }\n\n            let desiredControlIDs = desiredDivertedControlIDs(availableControls: allControls, identity: targetIdentity)\n            let isRecording = SettingsState.shared.recording\n            let recordingSessionID = isRecording ? SettingsState.shared.virtualButtonRecordingSessionID : nil\n            let monitoredControls = isRecording\n                ? allControls\n                : allControls.filter { desiredControlIDs.contains($0.controlID) }\n            let monitoredControlIDs = Set(monitoredControls.map(\\.controlID))\n            let reservedVirtualButtonNumber =\n                LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.reservedVirtualButtonNumber\n\n            if !isRecording {\n                let controlsToRestore = pendingReportingRestoreByControlID\n                    .filter { !desiredControlIDs.contains($0.key) }\n                if !controlsToRestore.isEmpty {\n                    let failedRestoreByControlID = restoreReportingState(\n                        controlsToRestore,\n                        using: transport,\n                        featureIndex: featureIndex,\n                        locationID: locationID,\n                        slot: slot,\n                        reason: \"apply native reporting to unmonitored controls\"\n                    )\n\n                    for controlID in Set(controlsToRestore.keys).subtracting(failedRestoreByControlID.keys) {\n                        pendingReportingRestoreByControlID.removeValue(forKey: controlID)\n                    }\n\n                    pendingReportingRestoreByControlID.merge(failedRestoreByControlID) { _, new in new }\n                }\n            }\n\n            if monitoredControls.isEmpty {\n                finishVirtualButtonRecordingPreparationIfNeeded(sessionID: recordingSessionID)\n                os_log(\n                    \"Pause Logitech control diversion until configuration changes: locationID=%{public}d slot=%{public}u device=%{public}@ recording=%{public}@\",\n                    log: Self.log,\n                    type: .info,\n                    locationID,\n                    slot,\n                    targetName,\n                    isRecording ? \"true\" : \"false\"\n                )\n\n                guard waitForReconfigurationOrStop() else {\n                    return\n                }\n\n                continue\n            }\n\n            let originalReportingByControlID = monitoredControls\n                .reduce(into: [UInt16: ReportingInfo]()) { result, control in\n                    guard let reportingInfo = readReportingInfo(\n                        for: control.controlID,\n                        using: transport,\n                        featureIndex: featureIndex\n                    ) else {\n                        return\n                    }\n\n                    result[control.controlID] = reportingInfo\n                }\n            let activeControlIDs = monitoredControls.compactMap { control -> UInt16? in\n                guard setDivertedWithRetry(true, for: control.controlID, using: transport, featureIndex: featureIndex)\n                else {\n                    os_log(\n                        \"Failed to enable Logitech control diversion: locationID=%{public}d slot=%{public}u cid=0x%{public}04X\",\n                        log: Self.log,\n                        type: .error,\n                        locationID,\n                        slot,\n                        control.controlID\n                    )\n                    return nil\n                }\n\n                return control.controlID\n            }\n\n            guard !activeControlIDs.isEmpty else {\n                finishVirtualButtonRecordingPreparationIfNeeded(sessionID: recordingSessionID)\n                os_log(\n                    \"Failed to enable any Logitech control diversion: locationID=%{public}d slot=%{public}u device=%{public}@\",\n                    log: Self.log,\n                    type: .error,\n                    locationID,\n                    slot,\n                    targetName\n                )\n\n                guard waitForReconfigurationOrStop() else {\n                    return\n                }\n\n                continue\n            }\n\n            let activeReportingByControlID = activeControlIDs\n                .reduce(into: [UInt16: ReportingInfo]()) { result, controlID in\n                    guard let reportingInfo = readReportingInfo(\n                        for: controlID,\n                        using: transport,\n                        featureIndex: featureIndex\n                    ) else {\n                        return\n                    }\n\n                    result[controlID] = reportingInfo\n                }\n\n            let controlSummary = monitoredControls.map { control in\n                let originalReporting = originalReportingByControlID[control.controlID]\n                let activeReporting = activeReportingByControlID[control.controlID]\n                return String(\n                    format: \"cid=0x%04X button=%d tid=0x%04X flags=%@ reporting=%@ mapped=0x%04X\",\n                    control.controlID,\n                    reservedVirtualButtonNumber,\n                    control.taskID,\n                    describeControlFlags(control.flags),\n                    describeReportingFlags(activeReporting?.flags ?? originalReporting?.flags ?? []),\n                    activeReporting?.mappedControlID ?? originalReporting?.mappedControlID ?? control.controlID\n                )\n            }\n            .joined(separator: \" | \")\n\n            os_log(\n                \"Logitech controls monitor enabled: locationID=%{public}d slot=%{public}u device=%{public}@ controls=%{public}@\",\n                log: Self.log,\n                type: .info,\n                locationID,\n                slot,\n                targetName,\n                controlSummary\n            )\n\n            finishVirtualButtonRecordingPreparationIfNeeded(sessionID: recordingSessionID)\n\n            var pressedControls = Set<UInt16>()\n            defer {\n                releaseButtonIfNeeded()\n\n                let failedRestoreByControlID = restoreReportingState(\n                    originalReportingByControlID,\n                    using: transport,\n                    featureIndex: featureIndex,\n                    locationID: locationID,\n                    slot: slot,\n                    reason: \"restore original reporting\"\n                )\n\n                pendingReportingRestoreByControlID.merge(failedRestoreByControlID) { _, new in new }\n                for controlID in Set(originalReportingByControlID.keys).subtracting(failedRestoreByControlID.keys) {\n                    pendingReportingRestoreByControlID.removeValue(forKey: controlID)\n                }\n            }\n\n            while shouldContinueRunning() {\n                let reconfigResult = consumeReconfigurationRequest()\n                if reconfigResult.needed {\n                    if reconfigResult.forced {\n                        os_log(\n                            \"Restart Logitech control monitor (forced, e.g. device reconnect): locationID=%{public}d slot=%{public}u device=%{public}@\",\n                            log: Self.log,\n                            type: .info,\n                            locationID,\n                            slot,\n                            targetName\n                        )\n                        break\n                    }\n\n                    let newDesiredControlIDs = desiredDivertedControlIDs(\n                        availableControls: allControls, identity: targetIdentity\n                    )\n                    let newIsRecording = SettingsState.shared.recording\n\n                    if newDesiredControlIDs != desiredControlIDs || newIsRecording != isRecording {\n                        os_log(\n                            \"Restart Logitech control monitor to refresh diverted controls: locationID=%{public}d slot=%{public}u device=%{public}@\",\n                            log: Self.log,\n                            type: .info,\n                            locationID,\n                            slot,\n                            targetName\n                        )\n                        break\n                    }\n                }\n\n                guard let report = monitorTarget.notificationEndpoint.waitForHIDPPNotification(\n                    timeout: Constants.notificationTimeout,\n                    matching: { response in\n                        Self.isDivertedButtonsNotification(response, featureIndex: featureIndex, slot: slot)\n                    },\n                    until: { [weak self] in self?.shouldContinueRunning() == true }\n                ) else {\n                    continue\n                }\n\n                let activeControls = Self.parseDivertedButtonsNotification(report).intersection(monitoredControlIDs)\n                let changedControls = activeControls.symmetricDifference(pressedControls).sorted()\n                pressedControls = activeControls\n\n                for controlID in changedControls {\n                    let isPressed = activeControls.contains(controlID)\n                    os_log(\n                        \"Logitech reprogrammable control event: locationID=%{public}d slot=%{public}u device=%{public}@ cid=0x%{public}04X button=%{public}d state=%{public}@ active=%{public}@\",\n                        log: Self.log,\n                        type: .info,\n                        locationID,\n                        slot,\n                        targetName,\n                        controlID,\n                        reservedVirtualButtonNumber,\n                        isPressed ? \"down\" : \"up\",\n                        activeControls.map { String(format: \"0x%04X\", $0) }.sorted().joined(separator: \",\")\n                    )\n\n                    device.markActive(reason: \"Received Logitech reprogrammable control event\")\n\n                    let modifierFlags = ModifierState.shared.currentFlags\n                    let controlIdentity = LogitechControlIdentity(\n                        controlID: Int(controlID),\n                        productID: targetIdentity?.productID,\n                        serialNumber: targetIdentity?.serialNumber\n                    )\n\n                    if isRecording {\n                        if isPressed {\n                            DispatchQueue.main.async {\n                                SettingsState.shared.recordedVirtualButtonEvent = .init(\n                                    button: .logitechControl(controlIdentity),\n                                    modifierFlags: modifierFlags\n                                )\n                            }\n                        }\n                        continue\n                    }\n\n                    let mouseLocation = CGEvent(source: nil)?.location ?? .zero\n                    let mouseLocationPid = mouseLocation.topmostWindowOwnerPid\n                        ?? NSWorkspace.shared.frontmostApplication?.processIdentifier\n                    let display = ScreenManager.shared.currentScreenNameSnapshot\n\n                    let logitechContext = LogitechEventContext(\n                        device: device,\n                        pid: mouseLocationPid,\n                        display: display,\n                        mouseLocation: mouseLocation,\n                        controlIdentity: controlIdentity,\n                        isPressed: isPressed,\n                        modifierFlags: modifierFlags\n                    )\n\n                    let handledInternally = EventThread.shared.performAndWait {\n                        EventTransformerManager.shared.handleLogitechControlEvent(logitechContext)\n                    } ?? false\n\n                    guard !handledInternally else {\n                        continue\n                    }\n\n                    postSyntheticButton(\n                        button: reservedVirtualButtonNumber,\n                        down: isPressed\n                    )\n                }\n            }\n        }\n    }\n\n    private func waitForReconfigurationOrStop() -> Bool {\n        while shouldContinueRunning() {\n            if consumeReconfigurationRequest().needed {\n                return true\n            }\n\n            Thread.sleep(forTimeInterval: Constants.notificationTimeout)\n        }\n\n        return false\n    }\n\n    private func finishVirtualButtonRecordingPreparationIfNeeded(sessionID: UUID?) {\n        guard let sessionID else {\n            return\n        }\n\n        DispatchQueue.main.async {\n            SettingsState.shared.finishVirtualButtonRecordingPreparation(\n                for: self.device.id,\n                sessionID: sessionID\n            )\n        }\n    }\n\n    private func findMonitoredControls(using transport: LogitechHIDPPTransport, featureIndex: UInt8) -> [ControlInfo] {\n        let controls = fetchControls(using: transport, featureIndex: featureIndex)\n        return controls\n            .filter(Self.shouldMonitor)\n            .sorted { lhs, rhs in\n                if lhs.controlID != rhs.controlID {\n                    return lhs.controlID < rhs.controlID\n                }\n\n                return lhs.taskID < rhs.taskID\n            }\n    }\n\n    private func resolveMonitorTarget() -> MonitorTarget? {\n        if device.pointerDevice.transport == PointerDeviceTransportName.bluetoothLowEnergy {\n            return buildDirectMonitorTarget()\n        }\n\n        guard let receiverChannel = provider.openReceiverChannel(for: device.pointerDevice) else {\n            return nil\n        }\n\n        return resolveMonitorTarget(using: receiverChannel)\n    }\n\n    private func buildDirectMonitorTarget() -> MonitorTarget? {\n        guard let transport = LogitechHIDPPTransport(device: device.pointerDevice, deviceIndex: nil),\n              let featureIndex = transport.featureIndex(for: .reprogControlsV4) else {\n            return nil\n        }\n\n        let controls = findMonitoredControls(using: transport, featureIndex: featureIndex)\n        guard !controls.isEmpty else {\n            return nil\n        }\n\n        let identity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: device.pointerDevice.locationID ?? 0,\n            slot: 0,\n            kind: .mouse,\n            name: device.productName ?? device.name,\n            serialNumber: device.serialNumber,\n            productID: device.productID,\n            batteryLevel: device.batteryLevel\n        )\n\n        return MonitorTarget(\n            slot: LogitechHIDPPDeviceMetadataProvider.Constants.receiverIndex,\n            identity: identity,\n            transport: transport,\n            featureIndex: featureIndex,\n            controls: controls,\n            notificationEndpoint: directNotificationEndpoint()\n        )\n    }\n\n    private func directNotificationEndpoint() -> HIDPPNotificationEndpoint {\n        directDeviceReportObservationToken = nil\n        let endpoint = HIDPPNotificationEndpoint()\n        directDeviceReportObservationToken = device.pointerDevice.observeReport { _, report in\n            endpoint.handleInputReport(report)\n        }\n        return endpoint\n    }\n\n    private func resolveTargetDevice(\n        using receiverChannel: LogitechReceiverChannel,\n        discovery: LogitechHIDPPDeviceMetadataProvider.ReceiverPointingDeviceDiscovery\n    ) -> TargetDevice? {\n        let desiredProductID = device.pointerDevice.productID\n        let desiredSerial = device.pointerDevice\n            .serialNumber?\n            .lowercased()\n            .trimmingCharacters(in: .whitespacesAndNewlines)\n        let desiredName = (device.pointerDevice.product ?? device.pointerDevice.name)\n            .lowercased()\n            .trimmingCharacters(in: .whitespacesAndNewlines)\n\n        // Try to match device to a slot using discovery results directly,\n        // avoiding a second full slot scan.\n        let matched: ReceiverLogicalDeviceIdentity? =\n            // Match by serial number\n            discovery.identities.first {\n                guard let serial = $0.serialNumber?.lowercased().trimmingCharacters(in: .whitespacesAndNewlines),\n                      let desired = desiredSerial, !desired.isEmpty else {\n                    return false\n                }\n                return serial == desired\n            }\n            // Match by product ID\n            ?? discovery.identities.first {\n                guard let pid = $0.productID, let desired = desiredProductID else {\n                    return false\n                }\n                return pid == desired\n            }\n            // Match by name\n            ?? discovery.identities.first {\n                $0.name.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) == desiredName\n            }\n\n        if let matched {\n            return TargetDevice(slot: matched.slot, identity: matched)\n        }\n\n        // Fallback: use the original slot matching via HID++ pairing info\n        if let slot = provider.receiverSlot(for: device.pointerDevice, using: receiverChannel) {\n            let identity = discovery.identities.first { $0.slot == slot }\n            return TargetDevice(slot: slot, identity: identity)\n        }\n\n        return nil\n    }\n\n    private func resolveMonitorTarget(using receiverChannel: LogitechReceiverChannel) -> MonitorTarget? {\n        let discovery = provider.receiverPointingDeviceDiscovery(for: device.pointerDevice, using: receiverChannel)\n\n        if let targetDevice = resolveTargetDevice(using: receiverChannel, discovery: discovery),\n           let target = buildMonitorTarget(\n               slot: targetDevice.slot,\n               identity: targetDevice.identity,\n               using: receiverChannel\n           ) {\n            return target\n        }\n\n        // Only scan connected slots instead of all 6\n        let connectedSlots = Set(discovery.connectionSnapshots.compactMap { slot, snapshot in\n            snapshot.isConnected ? slot : nil\n        })\n        // Prefer connected slots; fall back to identity slots or all 1...6\n        // when connection snapshots are unavailable.\n        let identitySlots = Array(Set(discovery.identities.map(\\.slot))).sorted()\n        let candidateSlots: [UInt8]\n        if !connectedSlots.isEmpty {\n            candidateSlots = identitySlots.isEmpty\n                ? Array(connectedSlots.sorted())\n                : identitySlots.filter { connectedSlots.contains($0) }\n        } else if !identitySlots.isEmpty {\n            candidateSlots = identitySlots\n        } else {\n            candidateSlots = Array(UInt8(1) ... UInt8(6))\n        }\n\n        let scannedTargets = candidateSlots.compactMap { slot in\n            buildMonitorTarget(\n                slot: slot,\n                identity: discovery.identities.first { $0.slot == slot },\n                using: receiverChannel\n            )\n        }\n\n        if scannedTargets.count == 1 {\n            let target = scannedTargets[0]\n            os_log(\n                \"Resolved Logitech monitor target by slot scan: receiver=%{public}@ slot=%{public}u name=%{public}@\",\n                log: Self.log,\n                type: .info,\n                device.productName ?? device.name,\n                target.slot,\n                target.identity?.name ?? \"(nil)\"\n            )\n            return target\n        }\n\n        let candidatesDescription = scannedTargets.map { target in\n            let name = target.identity?.name ?? \"(nil)\"\n            let firstControl = target.controls.first\n            return String(\n                format: \"slot=%u name=%@ firstCID=0x%04X count=%u\",\n                target.slot,\n                name,\n                firstControl?.controlID ?? 0,\n                target.controls.count\n            )\n        }\n        .joined(separator: \", \")\n\n        os_log(\n            \"Failed to resolve Logitech monitor target: receiver=%{public}@ discoveryCount=%{public}u candidates=%{public}@\",\n            log: Self.log,\n            type: .info,\n            device.productName ?? device.name,\n            UInt32(discovery.identities.count),\n            candidatesDescription\n        )\n        return nil\n    }\n\n    private func buildMonitorTarget(\n        slot: UInt8,\n        identity: ReceiverLogicalDeviceIdentity?,\n        using receiverChannel: LogitechReceiverChannel\n    ) -> MonitorTarget? {\n        guard let transport = LogitechHIDPPTransport(device: receiverChannel, deviceIndex: slot),\n              let featureIndex = transport.featureIndex(for: .reprogControlsV4)\n        else {\n            return nil\n        }\n\n        let controls = findMonitoredControls(using: transport, featureIndex: featureIndex)\n        guard !controls.isEmpty else {\n            return nil\n        }\n\n        return MonitorTarget(\n            slot: slot,\n            identity: identity,\n            transport: transport,\n            featureIndex: featureIndex,\n            controls: controls,\n            notificationEndpoint: receiverChannel\n        )\n    }\n\n    private static func shouldMonitor(_ control: ControlInfo) -> Bool {\n        guard control.flags.contains(.mouseButton), !control.flags.contains(.virtual) else {\n            return false\n        }\n\n        let isDivertable = control.flags.contains(.divertable) || control.flags.contains(.persistentlyDivertable)\n        guard isDivertable else {\n            return false\n        }\n\n        guard !LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.nativeControlIDs\n            .contains(control.controlID) else {\n            return false\n        }\n\n        if LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.gestureButtonControlIDs.contains(control.controlID)\n            || LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.gestureButtonTaskIDs.contains(control.taskID) {\n            return true\n        }\n\n        if control.flags.contains(.rawXY) {\n            return true\n        }\n\n        return control.controlID >= 0x00C0 || control.taskID >= 0x0090\n    }\n\n    private func observeConfigurationChangesIfNeeded() {\n        guard subscriptions.isEmpty else {\n            return\n        }\n\n        ConfigurationState.shared\n            .$configuration\n            .dropFirst()\n            .sink { [weak self] _ in\n                self?.requestReconfiguration()\n            }\n            .store(in: &subscriptions)\n\n        SettingsState.shared\n            .$recording\n            .dropFirst()\n            .sink { [weak self] _ in\n                self?.requestReconfiguration()\n            }\n            .store(in: &subscriptions)\n\n        ScreenManager.shared\n            .$currentScreenName\n            .dropFirst()\n            .sink { [weak self] _ in\n                self?.requestReconfiguration()\n            }\n            .store(in: &subscriptions)\n\n        NSWorkspace.shared\n            .notificationCenter\n            .publisher(for: NSWorkspace.didActivateApplicationNotification)\n            .sink { [weak self] _ in\n                self?.requestReconfiguration()\n            }\n            .store(in: &subscriptions)\n    }\n\n    func requestReconfiguration() {\n        stateLock.lock()\n        needsReconfiguration = true\n        stateLock.unlock()\n    }\n\n    func requestForcedReconfiguration() {\n        stateLock.lock()\n        needsReconfiguration = true\n        needsForcedReconfiguration = true\n        stateLock.unlock()\n    }\n\n    private func consumeReconfigurationRequest() -> (needed: Bool, forced: Bool) {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n\n        guard needsReconfiguration else {\n            return (false, false)\n        }\n\n        let forced = needsForcedReconfiguration\n        needsReconfiguration = false\n        needsForcedReconfiguration = false\n        return (true, forced)\n    }\n\n    private func desiredDivertedControlIDs(\n        availableControls: [ControlInfo],\n        identity: ReceiverLogicalDeviceIdentity?\n    ) -> Set<UInt16> {\n        if SettingsState.shared.recording {\n            return Set(availableControls.map(\\.controlID))\n        }\n\n        let mouseLocation = CGEvent(source: nil)?.location ?? .zero\n        let mouseLocationPid = mouseLocation.topmostWindowOwnerPid\n            ?? NSWorkspace.shared.frontmostApplication?.processIdentifier\n        let scheme = ConfigurationState.shared.configuration.matchScheme(\n            withDevice: device,\n            withPid: mouseLocationPid,\n            withDisplay: ScreenManager.shared.currentScreenNameSnapshot\n        )\n\n        let directMappings: [UInt16] = (scheme.buttons.mappings ?? [])\n            .compactMap { (mapping: Scheme.Buttons.Mapping) -> UInt16? in\n                guard let logiButton = mapping.button?.logitechControl else {\n                    return nil\n                }\n\n                guard matches(logiButton: logiButton, identity: identity) else {\n                    return nil\n                }\n\n                return logiButton.controlIDValue\n            }\n\n        let autoScrollControlID: UInt16? = {\n            guard scheme.buttons.autoScroll.enabled ?? false,\n                  let logiButton = scheme.buttons.autoScroll.trigger?.button?.logitechControl,\n                  matches(logiButton: logiButton, identity: identity) else {\n                return nil\n            }\n            return logiButton.controlIDValue\n        }()\n\n        let gestureControlID: UInt16? = {\n            guard scheme.buttons.gesture.enabled ?? false,\n                  let logiButton = scheme.buttons.gesture.trigger?.button?.logitechControl,\n                  matches(logiButton: logiButton, identity: identity) else {\n                return nil\n            }\n            return logiButton.controlIDValue\n        }()\n\n        return Set(directMappings + [autoScrollControlID, gestureControlID].compactMap(\\.self))\n            .intersection(availableControls.map(\\.controlID))\n    }\n\n    private func matches(logiButton: LogitechControlIdentity, identity: ReceiverLogicalDeviceIdentity?) -> Bool {\n        if let configuredSerialNumber = logiButton.serialNumber {\n            guard let serialNumber = identity?.serialNumber else {\n                return false\n            }\n            return configuredSerialNumber.caseInsensitiveCompare(serialNumber) == .orderedSame\n        }\n\n        if let configuredProductID = logiButton.productID {\n            guard let productID = identity?.productID else {\n                return false\n            }\n            return configuredProductID == productID\n        }\n\n        return logiButton.serialNumber == nil && logiButton.productID == nil\n    }\n\n    private func fetchControls(using transport: LogitechHIDPPTransport, featureIndex: UInt8) -> [ControlInfo] {\n        guard let countResponse = transport.request(\n            featureIndex: featureIndex,\n            function: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.getControlCountFunction,\n            parameters: []\n        ), let count = countResponse.payload.first else {\n            return []\n        }\n\n        return (0 ..< count).compactMap { readControlInfo(index: $0, using: transport, featureIndex: featureIndex) }\n    }\n\n    private func readControlInfo(\n        index: UInt8,\n        using transport: LogitechHIDPPTransport,\n        featureIndex: UInt8\n    ) -> ControlInfo? {\n        guard let response = transport.request(\n            featureIndex: featureIndex,\n            function: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.getControlInfoFunction,\n            parameters: [index]\n        ) else {\n            return nil\n        }\n\n        let payload = response.payload\n        guard payload.count >= 9 else {\n            return nil\n        }\n\n        let controlID = UInt16(payload[0]) << 8 | UInt16(payload[1])\n        let taskID = UInt16(payload[2]) << 8 | UInt16(payload[3])\n        let flagsRaw = UInt16(payload[4]) | (UInt16(payload[8]) << 8)\n\n        return ControlInfo(\n            controlID: controlID,\n            taskID: taskID,\n            position: payload[5],\n            group: payload[6],\n            groupMask: payload[7],\n            flags: .init(rawValue: flagsRaw)\n        )\n    }\n\n    private func readReportingInfo(\n        for controlID: UInt16,\n        using transport: LogitechHIDPPTransport,\n        featureIndex: UInt8\n    ) -> ReportingInfo? {\n        guard let response = transport.request(\n            featureIndex: featureIndex,\n            function: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.getControlReportingFunction,\n            parameters: controlID.bytes\n        ), response.payload.count >= 3 else {\n            return nil\n        }\n\n        let mappedControlID: UInt16\n        if response.payload.count >= 5 {\n            let mapped = UInt16(response.payload[3]) << 8 | UInt16(response.payload[4])\n            mappedControlID = mapped == 0 ? controlID : mapped\n        } else {\n            mappedControlID = controlID\n        }\n\n        let flagsRaw = UInt16(response.payload[2]) |\n            (response.payload.count >= 6 ? UInt16(response.payload[5]) << 8 : 0)\n        return ReportingInfo(\n            flags: .init(rawValue: flagsRaw),\n            mappedControlID: mappedControlID\n        )\n    }\n\n    private func setDiverted(\n        _ enabled: Bool,\n        for controlID: UInt16,\n        using transport: LogitechHIDPPTransport,\n        featureIndex: UInt8\n    ) -> Bool {\n        let flags = enabled\n            ? UInt8(LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.ReportingFlags.diverted.rawValue)\n            : 0\n        let changeBits: UInt8 = enabled ? 0x03 : 0x02\n\n        guard let response = transport.request(\n            featureIndex: featureIndex,\n            function: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.setControlReportingFunction,\n            parameters: controlID.bytes + [UInt8(changeBits | flags), 0x00, 0x00]\n        ), response.payload.count >= 2 else {\n            return false\n        }\n\n        let didEchoControlID = response.payload[0] == UInt8(controlID >> 8)\n            && response.payload[1] == UInt8(controlID & 0xFF)\n        if !didEchoControlID {\n            os_log(\n                \"Logitech setCidReporting did not echo control ID: cid=0x%{public}04X payload=%{public}@\",\n                log: Self.log,\n                type: .info,\n                controlID,\n                response.payload.map { String(format: \"%02X\", $0) }.joined(separator: \" \")\n            )\n\n            // Read back the reporting state to verify diversion actually took effect\n            guard let verifyReporting = readReportingInfo(\n                for: controlID, using: transport, featureIndex: featureIndex\n            ) else {\n                os_log(\n                    \"Logitech setCidReporting verification failed (read-back error): cid=0x%{public}04X\",\n                    log: Self.log, type: .error, controlID\n                )\n                return false\n            }\n            let actuallyDiverted = verifyReporting.flags.contains(.diverted)\n            guard actuallyDiverted == enabled else {\n                os_log(\n                    \"Logitech setCidReporting verification mismatch: cid=0x%{public}04X wanted=%{public}@ actual=%{public}@\",\n                    log: Self.log, type: .error, controlID,\n                    enabled ? \"diverted\" : \"native\",\n                    actuallyDiverted ? \"diverted\" : \"native\"\n                )\n                return false\n            }\n        }\n\n        return true\n    }\n\n    private func setDivertedWithRetry(\n        _ enabled: Bool,\n        for controlID: UInt16,\n        using transport: LogitechHIDPPTransport,\n        featureIndex: UInt8,\n        maxAttempts: Int = 3,\n        retryDelay: TimeInterval = 0.05\n    ) -> Bool {\n        guard maxAttempts >= 1 else {\n            return false\n        }\n        for attempt in 1 ... maxAttempts {\n            if setDiverted(enabled, for: controlID, using: transport, featureIndex: featureIndex) {\n                return true\n            }\n\n            guard attempt < maxAttempts, shouldContinueRunning() else {\n                break\n            }\n\n            os_log(\n                \"Logitech setCidReporting retry %{public}d/%{public}d: cid=0x%{public}04X\",\n                log: Self.log, type: .info,\n                attempt, maxAttempts, controlID\n            )\n            Thread.sleep(forTimeInterval: retryDelay)\n        }\n        return false\n    }\n\n    private func restoreReportingState(\n        _ reportingByControlID: [UInt16: ReportingInfo],\n        using transport: LogitechHIDPPTransport,\n        featureIndex: UInt8,\n        locationID: Int,\n        slot: UInt8,\n        reason: StaticString\n    ) -> [UInt16: ReportingInfo] {\n        reportingByControlID.reduce(into: [UInt16: ReportingInfo]()) { result, entry in\n            let (controlID, reportingInfo) = entry\n            let shouldBeDiverted = reportingInfo.flags.contains(.diverted)\n\n            guard setDiverted(shouldBeDiverted, for: controlID, using: transport, featureIndex: featureIndex) else {\n                os_log(\n                    \"%{public}s failed: locationID=%{public}d slot=%{public}u cid=0x%{public}04X target=%{public}@\",\n                    log: Self.log,\n                    type: .error,\n                    String(describing: reason),\n                    locationID,\n                    slot,\n                    controlID,\n                    shouldBeDiverted ? \"diverted\" : \"native\"\n                )\n                result[controlID] = reportingInfo\n                return\n            }\n\n            guard let currentReportingInfo = readReportingInfo(\n                for: controlID,\n                using: transport,\n                featureIndex: featureIndex\n            ) else {\n                os_log(\n                    \"%{public}s verification failed: locationID=%{public}d slot=%{public}u cid=0x%{public}04X\",\n                    log: Self.log,\n                    type: .error,\n                    String(describing: reason),\n                    locationID,\n                    slot,\n                    controlID\n                )\n                result[controlID] = reportingInfo\n                return\n            }\n\n            let isDiverted = currentReportingInfo.flags.contains(.diverted)\n            guard isDiverted == shouldBeDiverted else {\n                os_log(\n                    \"%{public}s verification mismatch: locationID=%{public}d slot=%{public}u cid=0x%{public}04X target=%{public}@ actual=%{public}@ reporting=%{public}@\",\n                    log: Self.log,\n                    type: .error,\n                    String(describing: reason),\n                    locationID,\n                    slot,\n                    controlID,\n                    shouldBeDiverted ? \"diverted\" : \"native\",\n                    isDiverted ? \"diverted\" : \"native\",\n                    describeReportingFlags(currentReportingInfo.flags)\n                )\n                result[controlID] = reportingInfo\n                return\n            }\n        }\n    }\n\n    private func shouldContinueRunning() -> Bool {\n        stateLock.lock()\n        defer { stateLock.unlock() }\n        return running && !Thread.current.isCancelled\n    }\n\n    private func postSyntheticButton(button: Int, down: Bool) {\n        stateLock.lock()\n        let shouldPost = down ? pressedButtons.insert(button).inserted : pressedButtons.remove(button) != nil\n        stateLock.unlock()\n\n        guard shouldPost else {\n            return\n        }\n\n        SyntheticMouseButtonEventEmitter.post(button: button, down: down)\n    }\n\n    private func releaseButtonIfNeeded() {\n        stateLock.lock()\n        let buttonsToRelease = pressedButtons\n        pressedButtons.removeAll()\n        stateLock.unlock()\n\n        for button in buttonsToRelease {\n            SyntheticMouseButtonEventEmitter.post(button: button, down: false)\n        }\n    }\n\n    static func isDivertedButtonsNotification(_ report: [UInt8], featureIndex: UInt8, slot: UInt8) -> Bool {\n        guard report.count >= 4,\n              [LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID,\n               LogitechHIDPPDeviceMetadataProvider.Constants.longReportID].contains(report[0]),\n              report[1] == slot,\n              report[2] == featureIndex\n        else {\n            return false\n        }\n\n        return (report[3] >> 4) == 0x00\n    }\n\n    static func parseDivertedButtonsNotification(_ report: [UInt8]) -> Set<UInt16> {\n        let payload = Array(report.dropFirst(4))\n        guard payload.count >= 2 else {\n            return []\n        }\n\n        var controls = Set<UInt16>()\n        var index = 0\n        while index + 1 < payload.count {\n            let controlID = UInt16(payload[index]) << 8 | UInt16(payload[index + 1])\n            guard controlID != 0 else {\n                break\n            }\n\n            controls.insert(controlID)\n            index += 2\n        }\n\n        return controls\n    }\n\n    private func logAvailableControls(\n        transport: LogitechHIDPPTransport,\n        featureIndex: UInt8,\n        slot: UInt8,\n        locationID: Int\n    ) {\n        let controls = fetchControls(using: transport, featureIndex: featureIndex)\n        guard !controls.isEmpty else {\n            os_log(\n                \"No Logitech reprogrammable controls discovered: locationID=%{public}d slot=%{public}u\",\n                log: Self.log,\n                type: .info,\n                locationID,\n                slot\n            )\n            return\n        }\n\n        let summary = controls.map { control -> String in\n            let reporting = readReportingInfo(for: control.controlID, using: transport, featureIndex: featureIndex)\n            return String(\n                format: \"cid=0x%04X tid=0x%04X pos=%u group=%u mask=0x%02X flags=%@ reporting=%@ mapped=0x%04X\",\n                control.controlID,\n                control.taskID,\n                control.position,\n                control.group,\n                control.groupMask,\n                describeControlFlags(control.flags),\n                describeReportingFlags(reporting?.flags ?? []),\n                reporting?.mappedControlID ?? control.controlID\n            )\n        }\n        .joined(separator: \" | \")\n\n        os_log(\n            \"Logitech REPROG_CONTROLS_V4 dump: locationID=%{public}d slot=%{public}u controls=%{public}@\",\n            log: Self.log,\n            type: .info,\n            locationID,\n            slot,\n            summary\n        )\n    }\n\n    private func describeControlFlags(_ flags: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4\n        .ControlFlags) -> String {\n        var parts = [String]()\n        if flags.contains(.mouseButton) {\n            parts.append(\"mse\")\n        }\n        if flags.contains(.reprogrammable) {\n            parts.append(\"reprogrammable\")\n        }\n        if flags.contains(.divertable) {\n            parts.append(\"divertable\")\n        }\n        if flags.contains(.persistentlyDivertable) {\n            parts.append(\"persistently_divertable\")\n        }\n        if flags.contains(.virtual) {\n            parts.append(\"virtual\")\n        }\n        if flags.contains(.rawXY) {\n            parts.append(\"raw_xy\")\n        }\n        if flags.contains(.forceRawXY) {\n            parts.append(\"force_raw_xy\")\n        }\n        return parts.isEmpty ? \"none\" : parts.joined(separator: \",\")\n    }\n\n    private func describeReportingFlags(_ flags: LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4\n        .ReportingFlags) -> String {\n        var parts = [String]()\n        if flags.contains(.diverted) {\n            parts.append(\"diverted\")\n        }\n        if flags.contains(.persistentlyDiverted) {\n            parts.append(\"persistently_diverted\")\n        }\n        if flags.contains(.rawXYDiverted) {\n            parts.append(\"raw_xy_diverted\")\n        }\n        if flags.contains(.forceRawXYDiverted) {\n            parts.append(\"force_raw_xy_diverted\")\n        }\n        return parts.isEmpty ? \"default\" : parts.joined(separator: \",\")\n    }\n}\n\nprivate protocol HIDPPNotificationHandling: AnyObject {\n    func enableNotifications()\n    func waitForHIDPPNotification(\n        timeout: TimeInterval,\n        matching: @escaping ([UInt8]) -> Bool,\n        until shouldContinue: (() -> Bool)?\n    ) -> [UInt8]?\n}\n\nprivate final class HIDPPNotificationEndpoint: HIDPPNotificationHandling {\n    private static let maxBufferedReports = 64\n\n    private let lock = NSLock()\n    private let semaphore = DispatchSemaphore(value: 0)\n    private var bufferedReports = [[UInt8]]()\n\n    func enableNotifications() {}\n\n    func handleInputReport(_ report: Data) {\n        let bytes = [UInt8](report)\n        guard let reportID = bytes.first,\n              [LogitechHIDPPDeviceMetadataProvider.Constants.shortReportID,\n               LogitechHIDPPDeviceMetadataProvider.Constants.longReportID].contains(reportID) else {\n            return\n        }\n\n        lock.lock()\n        bufferedReports.append(bytes)\n        if bufferedReports.count > Self.maxBufferedReports {\n            bufferedReports.removeFirst(bufferedReports.count - Self.maxBufferedReports)\n        }\n        lock.unlock()\n        semaphore.signal()\n    }\n\n    func waitForHIDPPNotification(\n        timeout: TimeInterval,\n        matching: @escaping ([UInt8]) -> Bool,\n        until shouldContinue: (() -> Bool)? = nil\n    ) -> [UInt8]? {\n        let deadline = Date().addingTimeInterval(timeout)\n        while Date() < deadline {\n            if let shouldContinue, !shouldContinue() {\n                return nil\n            }\n\n            if let report = dequeueFirstMatchingReport(matching: matching) {\n                return report\n            }\n\n            let remaining = deadline.timeIntervalSinceNow\n            guard remaining > 0 else {\n                break\n            }\n\n            _ = semaphore.wait(timeout: .now() + min(remaining, 0.01))\n        }\n\n        return dequeueFirstMatchingReport(matching: matching)\n    }\n\n    private func dequeueFirstMatchingReport(matching: ([UInt8]) -> Bool) -> [UInt8]? {\n        lock.lock()\n        defer { lock.unlock() }\n\n        guard let index = bufferedReports.firstIndex(where: matching) else {\n            return nil\n        }\n\n        return bufferedReports.remove(at: index)\n    }\n}\n\nextension LogitechReceiverChannel: HIDPPNotificationHandling {\n    func enableNotifications() {\n        enableWirelessNotifications()\n    }\n}\n\nprivate extension UInt16 {\n    var bytes: [UInt8] {\n        [UInt8(self >> 8), UInt8(self & 0xFF)]\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Device/VendorSpecific/PointerDevice+VendorSpecificDeviceContext.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport PointerKit\n\nextension PointerDevice: VendorSpecificDeviceContext {}\n"
  },
  {
    "path": "LinearMouse/Device/VendorSpecific/VendorSpecificDeviceMetadata.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nprotocol VendorSpecificDeviceContext {\n    var vendorID: Int? { get }\n    var productID: Int? { get }\n    var product: String? { get }\n    var name: String { get }\n    var serialNumber: String? { get }\n    var transport: String? { get }\n    var locationID: Int? { get }\n    var primaryUsagePage: Int? { get }\n    var primaryUsage: Int? { get }\n    var maxInputReportSize: Int? { get }\n    var maxOutputReportSize: Int? { get }\n    var maxFeatureReportSize: Int? { get }\n\n    func performSynchronousOutputReportRequest(\n        _ report: Data,\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool\n    ) -> Data?\n}\n\nstruct VendorSpecificDeviceMatcher {\n    let vendorID: Int?\n    let productIDs: Set<Int>?\n    let transports: Set<String>?\n\n    func matches(device: VendorSpecificDeviceContext) -> Bool {\n        if let vendorID, device.vendorID != vendorID {\n            return false\n        }\n\n        if let productIDs {\n            guard let productID = device.productID,\n                  productIDs.contains(productID) else {\n                return false\n            }\n        }\n\n        if let transports {\n            guard let transport = device.transport,\n                  transports.contains(transport) else {\n                return false\n            }\n        }\n\n        return true\n    }\n}\n\nstruct VendorSpecificDeviceMetadata: Equatable {\n    let name: String?\n    let batteryLevel: Int?\n}\n\nprotocol VendorSpecificDeviceMetadataProvider {\n    var matcher: VendorSpecificDeviceMatcher { get }\n    func metadata(for device: VendorSpecificDeviceContext) -> VendorSpecificDeviceMetadata?\n}\n\nextension VendorSpecificDeviceMetadataProvider {\n    func matches(device: VendorSpecificDeviceContext) -> Bool {\n        matcher.matches(device: device)\n    }\n}\n\nenum VendorSpecificDeviceMetadataRegistry {\n    static let providers: [VendorSpecificDeviceMetadataProvider] = [\n        LogitechHIDPPDeviceMetadataProvider()\n    ]\n\n    static func metadata(for device: VendorSpecificDeviceContext) -> VendorSpecificDeviceMetadata? {\n        for provider in providers where provider.matches(device: device) {\n            if let metadata = provider.metadata(for: device) {\n                return metadata\n            }\n        }\n\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTap/EventTap.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport ObservationToken\nimport os.log\n\nenum EventTap {}\n\nextension EventTap {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"EventTap\")\n\n    typealias Callback = (_ proxy: CGEventTapProxy, _ event: CGEvent) -> CGEvent?\n\n    private class ContextHolder {\n        var tap: CFMachPort?\n        let callback: Callback\n\n        init(_ callback: @escaping Callback) {\n            self.callback = callback\n        }\n    }\n\n    private static let callbackInvoker: CGEventTapCallBack = { proxy, type, event, refcon -> Unmanaged<CGEvent>? in\n        // If no refcon (aka userInfo) is passed in, just bypass the event.\n        guard let refcon else {\n            return Unmanaged.passUnretained(event)\n        }\n\n        // Get the tap and the callback from contextHolder.\n        let contextHolder = Unmanaged<ContextHolder>.fromOpaque(refcon).takeUnretainedValue()\n        let tap = contextHolder.tap\n        let callback = contextHolder.callback\n\n        switch type {\n        case .tapDisabledByUserInput:\n            return Unmanaged.passUnretained(event)\n\n        case .tapDisabledByTimeout:\n            os_log(\"EventTap disabled by timeout, re-enable it\", log: log, type: .error, String(describing: type))\n            guard let tap else {\n                os_log(\"Cannot find the tap\", log: log, type: .error, String(describing: type))\n                return Unmanaged.passUnretained(event)\n            }\n            CGEvent.tapEnable(tap: tap, enable: true)\n            return Unmanaged.passUnretained(event)\n\n        default:\n            let originalEvent = event\n\n            // If the callback returns nil, ignore the event.\n            guard let event = callback(proxy, event) else {\n                return nil\n            }\n\n            // If the callback returns a different event (e.g. a copy),\n            // use passRetained to transfer ownership to the caller.\n            if event === originalEvent {\n                return Unmanaged.passUnretained(event)\n            }\n            return Unmanaged.passRetained(event)\n        }\n    }\n\n    /**\n     Create an `EventTap` to observe the `events` and add it to the `runLoop`.\n\n     - Parameters:\n        - events: The event types to observe.\n        - runLoop: The target `RunLoop` to run the event tap.\n        - callback: The callback of the event tap.\n     */\n    static func observe(\n        _ events: [CGEventType],\n        place: CGEventTapPlacement = .headInsertEventTap,\n        at runLoop: RunLoop = .current,\n        callback: @escaping Callback\n    ) throws -> ObservationToken {\n        // Create a context holder. The lifetime of contextHolder should be the same as ObservationToken's.\n        let contextHolder = ContextHolder(callback)\n\n        // Create event tap.\n        let eventsOfInterest = events.reduce(CGEventMask(0)) { $0 | (1 << $1.rawValue) }\n        guard let tap = CGEvent.tapCreate(\n            tap: .cghidEventTap,\n            place: place,\n            options: .defaultTap,\n            eventsOfInterest: eventsOfInterest,\n            callback: callbackInvoker,\n            userInfo: Unmanaged.passUnretained(contextHolder).toOpaque()\n        ) else {\n            throw EventTapError.failedToCreate\n        }\n\n        // Attach tap to contextHolder.\n        contextHolder.tap = tap\n\n        // Create and add run loop source to the run loop.\n        let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)\n        let cfRunLoop = runLoop.getCFRunLoop()\n        CFRunLoopAddSource(cfRunLoop, runLoopSource, .commonModes)\n\n        // Periodically check if the tap is still enabled and re-enable it if needed.\n        // This recovers from cases where the system silently disables the tap\n        // (e.g. due to an invalid event or other transient errors).\n        let healthCheckTimer = Timer(timeInterval: 5, repeats: true) { _ in\n            guard CFMachPortIsValid(tap) else {\n                return\n            }\n            if !CGEvent.tapIsEnabled(tap: tap) {\n                os_log(\"EventTap found disabled, re-enabling\", log: log, type: .error)\n                CGEvent.tapEnable(tap: tap, enable: true)\n            }\n        }\n        runLoop.add(healthCheckTimer, forMode: .common)\n\n        return ObservationToken {\n            // The lifetime of contextHolder needs to be extended until the observation token is cancelled.\n            withExtendedLifetime(contextHolder) {\n                // Timer.invalidate() must be called from the thread where the timer was installed.\n                // Dispatch it to the target RunLoop; the remaining teardown calls are thread-safe.\n                CFRunLoopPerformBlock(cfRunLoop, CFRunLoopMode.commonModes.rawValue) {\n                    healthCheckTimer.invalidate()\n                }\n                CFRunLoopWakeUp(cfRunLoop)\n\n                CGEvent.tapEnable(tap: tap, enable: false)\n                CFRunLoopRemoveSource(cfRunLoop, runLoopSource, .commonModes)\n                CFMachPortInvalidate(tap)\n            }\n        }\n    }\n}\n\nenum EventTapError: Error {\n    case failedToCreate\n}\n"
  },
  {
    "path": "LinearMouse/EventTap/EventThread.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nprivate final class EventThreadResultBox<Value> {\n    var value: Value?\n}\n\n/// Manages a dedicated background thread with its own RunLoop for CGEvent processing.\n///\n/// All event transformer state access (transform, tick, deactivate) must happen on this thread.\n/// Use ``perform(_:)`` to dispatch work from other threads, and ``scheduleTimer(interval:repeats:handler:)``\n/// to create timers that fire on this thread.\nfinal class EventThread {\n    static let shared = EventThread()\n\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"EventThread\")\n\n    /// The RunLoop of the background thread. Nil when the thread is not running.\n    /// Exposed for `EventTap` to attach its `CFMachPort` source.\n    private(set) var runLoop: RunLoop?\n\n    /// Called on the event thread just before it stops.\n    /// Set by `GlobalEventTap` to wire up cleanup (e.g. cache invalidation) without tight coupling.\n    var onWillStop: (() -> Void)?\n\n    private var thread: Thread?\n    private let runLoopReady = DispatchSemaphore(value: 0)\n\n    init() {}\n\n    /// Whether the current thread is the event processing thread.\n    var isCurrent: Bool {\n        Thread.current === thread\n    }\n\n    // MARK: - Lifecycle\n\n    func start() {\n        guard thread == nil else {\n            return\n        }\n\n        let thread = Thread { [weak self] in\n            guard let self else {\n                return\n            }\n            let rl = RunLoop.current\n            // Keep the RunLoop alive even without event sources.\n            rl.add(Port(), forMode: .common)\n            self.runLoop = rl\n            self.runLoopReady.signal()\n            CFRunLoopRun()\n        }\n        thread.name = \"com.linearmouse.event-thread\"\n        thread.qualityOfService = .userInteractive\n        self.thread = thread\n        thread.start()\n\n        runLoopReady.wait()\n    }\n\n    /// Stop the event thread synchronously.\n    ///\n    /// Fires `onWillStop` on the event thread, waits for the RunLoop to exit,\n    /// then returns. This makes `stop(); start()` safe — the old thread is fully\n    /// torn down before a new one is created.\n    func stop() {\n        precondition(!isCurrent, \"EventThread.stop() must not be called from the event thread\")\n\n        guard let cfRunLoop = runLoop?.getCFRunLoop() else {\n            return\n        }\n\n        // Queue the willStop callback and CFRunLoopStop via FIFO ordering.\n        // All previously queued blocks (e.g. timer invalidations) complete first.\n        // thread/runLoop are kept alive until onWillStop finishes so that isCurrent\n        // and perform() still work correctly during teardown.\n        let done = DispatchSemaphore(value: 0)\n        CFRunLoopPerformBlock(cfRunLoop, CFRunLoopMode.commonModes.rawValue) { [weak self] in\n            self?.onWillStop?()\n            // Clear state after onWillStop so isCurrent was valid during teardown.\n            self?.thread?.cancel()\n            self?.thread = nil\n            self?.runLoop = nil\n        }\n        CFRunLoopPerformBlock(cfRunLoop, CFRunLoopMode.commonModes.rawValue) {\n            CFRunLoopStop(cfRunLoop)\n            done.signal()\n        }\n        CFRunLoopWakeUp(cfRunLoop)\n\n        // Wait for the event thread to finish. The teardown callback only posts\n        // non-blocking work back to the main queue.\n        done.wait()\n    }\n\n    // MARK: - Dispatch\n\n    /// Schedule a block to run on the event thread.\n    /// Returns `false` if the event thread is not running (block is not enqueued).\n    @discardableResult\n    func perform(_ block: @escaping () -> Void) -> Bool {\n        guard let cfRunLoop = runLoop?.getCFRunLoop() else {\n            return false\n        }\n        CFRunLoopPerformBlock(cfRunLoop, CFRunLoopMode.commonModes.rawValue, block)\n        CFRunLoopWakeUp(cfRunLoop)\n        return true\n    }\n\n    /// Execute a block on the event thread and wait for the result.\n    /// Returns `nil` if the event thread is not running.\n    func performAndWait<T>(_ block: @escaping () -> T) -> T? {\n        if isCurrent {\n            return block()\n        }\n\n        guard let cfRunLoop = runLoop?.getCFRunLoop() else {\n            return nil\n        }\n\n        let done = DispatchSemaphore(value: 0)\n        let result = EventThreadResultBox<T>()\n        CFRunLoopPerformBlock(cfRunLoop, CFRunLoopMode.commonModes.rawValue) {\n            result.value = block()\n            done.signal()\n        }\n        CFRunLoopWakeUp(cfRunLoop)\n        done.wait()\n        return result.value\n    }\n\n    // MARK: - Timer\n\n    /// Create a repeating or one-shot timer on the event thread's RunLoop.\n    /// Returns `nil` if the event thread is not running.\n    func scheduleTimer(\n        interval: TimeInterval,\n        repeats: Bool,\n        handler: @escaping () -> Void\n    ) -> EventThreadTimer? {\n        if isCurrent {\n            return scheduleTimerOnCurrentThread(interval: interval, repeats: repeats, handler: handler)\n        }\n\n        guard let timer = performAndWait({\n            self.scheduleTimerOnCurrentThread(interval: interval, repeats: repeats, handler: handler)\n        }) else {\n            return nil\n        }\n        return timer\n    }\n\n    private func scheduleTimerOnCurrentThread(\n        interval: TimeInterval,\n        repeats: Bool,\n        handler: @escaping () -> Void\n    ) -> EventThreadTimer? {\n        guard let runLoop else {\n            return nil\n        }\n\n        let timer = Timer(timeInterval: interval, repeats: repeats) { _ in\n            handler()\n        }\n        runLoop.add(timer, forMode: .common)\n        return EventThreadTimer(timer: timer, eventThread: self)\n    }\n}\n\n// MARK: - EventThreadTimer\n\n/// Lightweight wrapper around `Timer` that ensures invalidation happens on the correct thread.\n///\n/// When invalidated from the event thread, the underlying timer is stopped synchronously.\n/// When invalidated from any other thread, invalidation is dispatched to the event thread.\n/// On `deinit`, the timer is automatically invalidated — callers don't need manual cleanup.\nfinal class EventThreadTimer {\n    private var timer: Timer?\n    private weak var eventThread: EventThread?\n\n    init(timer: Timer, eventThread: EventThread) {\n        self.timer = timer\n        self.eventThread = eventThread\n    }\n\n    deinit {\n        invalidate()\n    }\n\n    /// Invalidate the underlying timer. Safe to call from any thread and idempotent.\n    func invalidate() {\n        guard let timer else {\n            return\n        }\n        self.timer = nil\n\n        if let eventThread, eventThread.isCurrent {\n            // Already on the event thread — invalidate synchronously.\n            timer.invalidate()\n        } else if let eventThread {\n            // Dispatch to the event thread where the timer was installed.\n            eventThread.perform {\n                timer.invalidate()\n            }\n        }\n        // If eventThread is nil (already deallocated), the RunLoop is gone\n        // and the timer is implicitly dead.\n    }\n\n    var isValid: Bool {\n        timer?.isValid ?? false\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTap/EventType.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nclass EventType {\n    static let all: [CGEventType] = [\n        .scrollWheel,\n        .leftMouseDown,\n        .leftMouseUp,\n        .leftMouseDragged,\n        .rightMouseDown,\n        .rightMouseUp,\n        .rightMouseDragged,\n        .otherMouseDown,\n        .otherMouseUp,\n        .otherMouseDragged,\n        .keyDown,\n        .keyUp,\n        .flagsChanged\n    ]\n\n    static let mouseMoved: CGEventType = .mouseMoved\n}\n"
  },
  {
    "path": "LinearMouse/EventTap/GlobalEventTap.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\nimport ObservationToken\nimport os.log\n\nclass GlobalEventTap {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"GlobalEventTap\")\n\n    static let shared = GlobalEventTap()\n\n    private var observationToken: ObservationToken?\n    private lazy var watchdog = GlobalEventTapWatchdog()\n    private let eventThread = EventThread.shared\n\n    init() {}\n\n    private func callback(_ event: CGEvent) -> CGEvent? {\n        ModifierState.shared.update(with: event)\n\n        let mouseEventView = MouseEventView(event)\n        let eventTransformer = EventTransformerManager.shared.get(\n            withCGEvent: event,\n            withSourcePid: mouseEventView.sourcePid,\n            withTargetPid: mouseEventView.targetPid,\n            withMouseLocationPid: mouseEventView.mouseLocationOwnerPid,\n            withDisplay: ScreenManager.shared.currentScreenNameSnapshot\n        )\n        return eventTransformer.transform(event)\n    }\n\n    func start() {\n        guard observationToken == nil else {\n            return\n        }\n\n        guard AccessibilityPermission.enabled else {\n            let alert = NSAlert()\n            alert.messageText = NSLocalizedString(\n                \"Failed to create GlobalEventTap: Accessibility permission not granted\",\n                comment: \"\"\n            )\n            alert.runModal()\n            return\n        }\n\n        var eventTypes: [CGEventType] = EventType.all\n        if SchemeState.shared.schemes.contains(where: { $0.pointer.redirectsToScroll ?? false }) ||\n            SchemeState.shared.schemes.contains(where: { $0.buttons.$autoScroll?.enabled ?? false }) ||\n            SchemeState.shared.schemes.contains(where: { $0.buttons.$gesture?.enabled ?? false }) {\n            eventTypes.append(EventType.mouseMoved)\n        }\n\n        eventThread.onWillStop = {\n            EventTransformerManager.shared.resetForRestart()\n        }\n        eventThread.start()\n\n        guard let observationResult = eventThread.performAndWait({\n            Result {\n                try EventTap.observe(eventTypes) { [weak self] in self?.callback($1) }\n            }\n        }) else {\n            eventThread.stop()\n            return\n        }\n\n        switch observationResult {\n        case let .success(token):\n            observationToken = token\n        case let .failure(error):\n            eventThread.stop()\n            NSAlert(error: error).runModal()\n            return\n        }\n\n        watchdog.start()\n    }\n\n    func stop() {\n        // Release the observation token, which dispatches timer invalidation\n        // to the event RunLoop (see EventTap.observe).\n        observationToken = nil\n\n        // EventThread.stop() fires onWillStop (which calls resetForRestart)\n        // then stops the RunLoop, all in FIFO order.\n        eventThread.stop()\n\n        watchdog.stop()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTap/GlobalEventTapWatchdog.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport os.log\n\nclass GlobalEventTapWatchdog {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"GlobalEventTapWatchdog\")\n\n    init() {}\n\n    deinit {\n        stop()\n    }\n\n    var timer: Timer?\n\n    func start() {\n        timer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { [weak self] _ in\n            guard let self else {\n                return\n            }\n\n            self.testAccessibilityPermission()\n        }\n    }\n\n    func stop() {\n        timer?.invalidate()\n        timer = nil\n    }\n\n    func testAccessibilityPermission() {\n        do {\n            try EventTap.observe([.scrollWheel]) { _, event in\n                event\n            }.removeLifetime()\n        } catch {\n            stop()\n            Application.restart()\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/AutoScrollTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport ApplicationServices\nimport Foundation\nimport os.log\n\nprivate let autoScrollIndicatorSize = CGSize(width: 48, height: 48)\n\nfinal class AutoScrollTransformer {\n    static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"AutoScroll\")\n\n    private static let deadZone: Double = 10\n    private static let maxScrollStep: Double = 160\n    private static let timerInterval: TimeInterval = 1.0 / 60.0\n    private static let maxAccessibilityParentDepth = 20\n    private static let accessibilityProbeRadius: CGFloat = 4\n    private static let excludedAccessibilityRoles: Set<String> = [\n        \"AXMenuBar\",\n        \"AXMenuBarItem\",\n        \"AXMenu\",\n        \"AXMenuItem\",\n        \"AXMenuButton\",\n        \"AXPopUpButton\",\n        \"AXTabGroup\",\n        \"AXToolbar\"\n    ]\n    private static let excludedAccessibilitySubroles: Set<String> = [\n        \"AXTabButton\",\n        \"AXMenuItem\",\n        \"AXSortButton\"\n    ]\n    private static let webContentAccessibilityRoles: Set<String> = [\n        \"AXWebArea\",\n        \"AXScrollArea\"\n    ]\n    private static let pressableAccessibilityRoles: Set<String> = [\n        \"AXLink\",\n        \"AXButton\",\n        \"AXCheckBox\",\n        \"AXRadioButton\",\n        \"AXPopUpButton\",\n        \"AXMenuButton\",\n        \"AXComboBox\",\n        \"AXDisclosureTriangle\",\n        \"AXSwitch\"\n    ]\n\n    private let trigger: Scheme.Buttons.Mapping\n    private let modes: [Scheme.Buttons.AutoScroll.Mode]\n    private let speed: Double\n    private let preserveNativeMiddleClick: Bool\n\n    private enum Session {\n        case toggle\n        case hold\n        case pendingToggleOrHold\n    }\n\n    private enum State {\n        case idle\n        case pendingPreservedClick(anchor: CGPoint, current: CGPoint, downEvent: CGEvent)\n        case active(anchor: CGPoint, current: CGPoint, session: Session)\n    }\n\n    private var state: State = .idle\n    private var suppressTriggerUp = false\n    private var suppressedExitMouseButton: CGMouseButton?\n    private var timer: EventThreadTimer?\n    private let indicatorController = AutoScrollIndicatorWindowController()\n\n    init(\n        trigger: Scheme.Buttons.Mapping,\n        modes: [Scheme.Buttons.AutoScroll.Mode],\n        speed: Double,\n        preserveNativeMiddleClick: Bool\n    ) {\n        self.trigger = trigger\n        self.modes = modes\n        self.speed = speed\n        self.preserveNativeMiddleClick = preserveNativeMiddleClick\n    }\n\n    deinit {\n        DispatchQueue.main.async { [indicatorController] in\n            indicatorController.hide()\n        }\n    }\n}\n\nextension AutoScrollTransformer: EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent? {\n        if case let .active(_, _, session) = state,\n           session == .toggle,\n           isAnyMouseDownEvent(event),\n           !matchesTriggerButton(event) {\n            suppressedExitMouseButton = MouseEventView(event).mouseButton\n            deactivate()\n            return nil\n        }\n\n        if let suppressedExitMouseButton,\n           isMouseUpEvent(event, for: suppressedExitMouseButton) {\n            self.suppressedExitMouseButton = nil\n            return nil\n        }\n\n        switch event.type {\n        case triggerMouseDownEventType:\n            return handleTriggerDown(event)\n        case triggerMouseUpEventType:\n            return handleTriggerUp(event)\n        case triggerMouseDraggedEventType, .mouseMoved:\n            return handlePointerMoved(event)\n        default:\n            return event\n        }\n    }\n\n    private var triggerMouseDownEventType: CGEventType {\n        triggerMouseButton.fixedCGEventType(of: .otherMouseDown)\n    }\n\n    private var triggerMouseUpEventType: CGEventType {\n        triggerMouseButton.fixedCGEventType(of: .otherMouseUp)\n    }\n\n    private var triggerMouseDraggedEventType: CGEventType {\n        triggerMouseButton.fixedCGEventType(of: .otherMouseDragged)\n    }\n\n    private var triggerMouseButton: CGMouseButton {\n        let defaultButton = UInt32(CGMouseButton.center.rawValue)\n        let buttonNumber = trigger.button?.syntheticMouseButtonNumber ?? Int(defaultButton)\n        return CGMouseButton(rawValue: UInt32(buttonNumber)) ?? .center\n    }\n\n    private var triggerIsLogitechControl: Bool {\n        trigger.button?.logitechControl != nil\n    }\n\n    private func handleTriggerDown(_ event: CGEvent) -> CGEvent? {\n        guard matchesTriggerButton(event) else {\n            return event\n        }\n\n        if case let .active(_, _, session) = state, session == .toggle {\n            guard hasToggleMode else {\n                return nil\n            }\n\n            deactivate()\n            suppressTriggerUp = true\n            return nil\n        }\n\n        guard matchesActivationTrigger(event) else {\n            return event\n        }\n\n        let activationHit = activationHit(for: event)\n        switch activationHit {\n        case .excludedChrome:\n            return event\n        case .pressable:\n            guard shouldPreserveNativeMiddleClick else {\n                break\n            }\n\n            if hasHoldMode {\n                let point = pointerLocation(for: event)\n                let downEvent = event.copy() ?? event\n                state = .pendingPreservedClick(anchor: point, current: point, downEvent: downEvent)\n                suppressTriggerUp = true\n                return nil\n            }\n\n            return event\n        case .nonPressable, .unknown, nil:\n            break\n        }\n\n        activate(at: pointerLocation(for: event), session: activationSession)\n        suppressTriggerUp = true\n        return nil\n    }\n\n    private func handleTriggerUp(_ event: CGEvent) -> CGEvent? {\n        guard matchesTriggerButton(event) else {\n            return event\n        }\n\n        guard suppressTriggerUp else {\n            return event\n        }\n\n        switch state {\n        case let .pendingPreservedClick(anchor, current, downEvent):\n            if !exceedsDeadZone(from: anchor, to: current) {\n                postDeferredNativeClick(from: downEvent)\n            }\n            state = .idle\n        case let .active(anchor, current, session):\n            switch session {\n            case .hold:\n                deactivate()\n            case .pendingToggleOrHold:\n                if exceedsDeadZone(from: anchor, to: current) {\n                    deactivate()\n                } else {\n                    state = .active(anchor: anchor, current: current, session: .toggle)\n                }\n            case .toggle:\n                break\n            }\n        case .idle:\n            break\n        }\n\n        suppressTriggerUp = false\n        return nil\n    }\n\n    private func handlePointerMoved(_ event: CGEvent) -> CGEvent? {\n        switch state {\n        case let .pendingPreservedClick(anchor, _, downEvent):\n            let point = pointerLocation(for: event)\n\n            if event.type == triggerMouseDraggedEventType,\n               exceedsDeadZone(from: anchor, to: point) {\n                activate(at: anchor, session: .hold)\n                state = .active(anchor: anchor, current: point, session: .hold)\n                let delta = CGVector(dx: point.x - anchor.x, dy: point.y - anchor.y)\n                DispatchQueue.main.async { [indicatorController] in\n                    indicatorController.update(delta: delta)\n                }\n                return nil\n            }\n\n            state = .pendingPreservedClick(anchor: anchor, current: point, downEvent: downEvent)\n\n            if event.type == triggerMouseDraggedEventType, suppressTriggerUp {\n                return nil\n            }\n\n            return event\n        case let .active(anchor, _, session):\n            let point = pointerLocation(for: event)\n            let resolvedSession: Session\n            let isDragOrLogitechMove = event.type == triggerMouseDraggedEventType\n                || (triggerIsLogitechControl && event.type == .mouseMoved)\n            if session == .pendingToggleOrHold,\n               isDragOrLogitechMove,\n               exceedsDeadZone(from: anchor, to: point) {\n                resolvedSession = .hold\n            } else {\n                resolvedSession = session\n            }\n\n            state = .active(anchor: anchor, current: point, session: resolvedSession)\n            let delta = CGVector(dx: point.x - anchor.x, dy: point.y - anchor.y)\n            DispatchQueue.main.async { [indicatorController] in\n                indicatorController.update(delta: delta)\n            }\n\n            if event.type == triggerMouseDraggedEventType, suppressTriggerUp {\n                return nil\n            }\n\n            return event\n        case .idle:\n            return event\n        }\n    }\n\n    var isAutoscrollActive: Bool {\n        if case .active = state {\n            return true\n        }\n        return false\n    }\n\n    private func matchesActivationTrigger(_ event: CGEvent) -> Bool {\n        guard matchesTriggerButton(event) else {\n            return false\n        }\n\n        return trigger.matches(modifierFlags: event.flags)\n    }\n\n    private func matchesTriggerButton(_ event: CGEvent) -> Bool {\n        guard let eventButton = MouseEventView(event).mouseButton else {\n            return false\n        }\n\n        return eventButton == triggerMouseButton\n    }\n\n    private func isAnyMouseDownEvent(_ event: CGEvent) -> Bool {\n        switch event.type {\n        case .leftMouseDown, .rightMouseDown, .otherMouseDown:\n            return true\n        default:\n            return false\n        }\n    }\n\n    private func isMouseUpEvent(_ event: CGEvent, for button: CGMouseButton) -> Bool {\n        guard let eventButton = MouseEventView(event).mouseButton else {\n            return false\n        }\n\n        switch event.type {\n        case .leftMouseUp, .rightMouseUp, .otherMouseUp:\n            return eventButton == button\n        default:\n            return false\n        }\n    }\n\n    private func activate(at point: CGPoint, session: Session) {\n        os_log(\n            \"Auto scroll activated (modes=%{public}@, button=%{public}d)\",\n            log: Self.log,\n            type: .info,\n            modes.map(\\.rawValue).joined(separator: \",\"),\n            Int(triggerMouseButton.rawValue)\n        )\n\n        suppressedExitMouseButton = nil\n        state = .active(anchor: point, current: point, session: session)\n        DispatchQueue.main.async { [indicatorController] in\n            indicatorController.show(at: point)\n            indicatorController.update(delta: .zero)\n        }\n        startTimerIfNeeded()\n    }\n\n    private func startTimerIfNeeded() {\n        guard timer == nil else {\n            return\n        }\n\n        timer = EventThread.shared.scheduleTimer(\n            interval: Self.timerInterval,\n            repeats: true\n        ) { [weak self] in\n            self?.tick()\n        }\n    }\n\n    private func tick() {\n        guard case let .active(anchor, current, _) = state else {\n            return\n        }\n\n        let horizontal = scrollAmount(for: anchor.x - current.x)\n        let vertical = scrollAmount(for: current.y - anchor.y)\n\n        guard horizontal != 0 || vertical != 0 else {\n            return\n        }\n\n        postContinuousScrollEvent(horizontal: horizontal, vertical: vertical)\n    }\n\n    private func scrollAmount(for delta: Double) -> Double {\n        let adjusted = abs(delta) - Self.deadZone\n        guard adjusted > 0 else {\n            return 0\n        }\n\n        let base = adjusted * speed * 0.12\n        let boost = sqrt(adjusted) * speed * 0.6\n        let value = min(Self.maxScrollStep, base + boost)\n\n        return delta.sign == .minus ? -value : value\n    }\n\n    private func postContinuousScrollEvent(horizontal: Double, vertical: Double) {\n        guard let event = CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .pixel,\n            wheelCount: 2,\n            wheel1: 0,\n            wheel2: 0,\n            wheel3: 0\n        ) else {\n            return\n        }\n\n        event.setDoubleValueField(.scrollWheelEventPointDeltaAxis1, value: vertical)\n        event.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis1, value: vertical)\n        event.setDoubleValueField(.scrollWheelEventPointDeltaAxis2, value: horizontal)\n        event.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis2, value: horizontal)\n        event.flags = []\n        event.post(tap: .cgSessionEventTap)\n    }\n\n    private var hasToggleMode: Bool {\n        modes.contains(.toggle)\n    }\n\n    private var hasHoldMode: Bool {\n        modes.contains(.hold)\n    }\n\n    private var activationSession: Session {\n        switch (hasToggleMode, hasHoldMode) {\n        case (true, true):\n            .pendingToggleOrHold\n        case (false, true):\n            .hold\n        default:\n            .toggle\n        }\n    }\n\n    private func pointerLocation(for event: CGEvent) -> CGPoint {\n        event.unflippedLocation\n    }\n\n    private func exceedsDeadZone(from anchor: CGPoint, to point: CGPoint) -> Bool {\n        abs(point.x - anchor.x) > Self.deadZone || abs(point.y - anchor.y) > Self.deadZone\n    }\n\n    private var shouldPreserveNativeMiddleClick: Bool {\n        guard preserveNativeMiddleClick,\n              hasToggleMode,\n              triggerMouseButton == .center,\n              trigger.modifierFlags.isEmpty else {\n            return false\n        }\n\n        return true\n    }\n\n    private func hitTestPoint(for event: CGEvent) -> CGPoint {\n        event.location\n    }\n\n    private func activationHit(for event: CGEvent) -> ActivationHit? {\n        guard AccessibilityPermission.enabled else {\n            return nil\n        }\n\n        // Use the event snapshot position instead of re-sampling the current cursor location.\n        // This keeps the AX hit-test anchored to the original click we are classifying.\n        let point = hitTestPoint(for: event)\n        let initialProbe = ActivationProbe(point: point, hit: hitAccessibilityElement(at: point))\n        let resolvedProbe = refineActivationProbe(from: initialProbe)\n        logAccessibilityHit(initial: initialProbe, resolved: resolvedProbe)\n        return resolvedProbe.hit\n    }\n\n    private func refineActivationProbe(from initialProbe: ActivationProbe) -> ActivationProbe {\n        guard initialProbe.hit.requiresAdditionalSampling else {\n            return initialProbe\n        }\n\n        // Browser accessibility trees can return a generic container chain for a point that\n        // is visually still inside a link. Probe a few nearby points and trust any result\n        // that clearly says \"do not start autoscroll\".\n        var bestProbe = initialProbe\n        for point in accessibilityProbePoints(around: initialProbe.point) {\n            let sampledProbe = ActivationProbe(point: point, hit: hitAccessibilityElement(at: point))\n            if sampledProbe.hit.suppressesAutoscroll {\n                return sampledProbe\n            }\n\n            if sampledProbe.hit.priority > bestProbe.hit.priority {\n                bestProbe = sampledProbe\n            }\n        }\n\n        return bestProbe\n    }\n\n    private func accessibilityProbePoints(around point: CGPoint) -> [CGPoint] {\n        let offsets = [\n            CGPoint.zero,\n            CGPoint(x: -Self.accessibilityProbeRadius, y: 0),\n            CGPoint(x: Self.accessibilityProbeRadius, y: 0),\n            CGPoint(x: 0, y: -Self.accessibilityProbeRadius),\n            CGPoint(x: 0, y: Self.accessibilityProbeRadius),\n            CGPoint(x: -Self.accessibilityProbeRadius, y: -Self.accessibilityProbeRadius),\n            CGPoint(x: -Self.accessibilityProbeRadius, y: Self.accessibilityProbeRadius),\n            CGPoint(x: Self.accessibilityProbeRadius, y: -Self.accessibilityProbeRadius),\n            CGPoint(x: Self.accessibilityProbeRadius, y: Self.accessibilityProbeRadius)\n        ]\n\n        return offsets.map { offset in\n            CGPoint(x: point.x + offset.x, y: point.y + offset.y)\n        }\n    }\n\n    private func hitAccessibilityElement(at point: CGPoint) -> ActivationHit {\n        let systemWideElement = AXUIElementCreateSystemWide()\n        var hitElement: AXUIElement?\n        let hitError = AXUIElementCopyElementAtPosition(systemWideElement, Float(point.x), Float(point.y), &hitElement)\n        guard hitError == .success else {\n            return .unknown(reason: \"hitTest.\\(describe(error: hitError))\", path: [])\n        }\n\n        guard let hitElement else {\n            return .nonPressable(path: [])\n        }\n\n        var currentElement: AXUIElement? = hitElement\n        var path: [String] = []\n        var isInsideWebContent = false\n        for _ in 0 ..< Self.maxAccessibilityParentDepth {\n            guard let element = currentElement else {\n                return .nonPressable(path: path)\n            }\n\n            let role: String?\n            switch requiredStringValue(of: kAXRoleAttribute as CFString, on: element) {\n            case let .success(value):\n                role = value\n            case let .failure(error):\n                return .unknown(reason: \"role.\\(describe(error: error))\", path: path)\n            }\n\n            let subrole: String?\n            switch optionalStringValue(of: kAXSubroleAttribute as CFString, on: element) {\n            case let .success(value):\n                subrole = value\n            case let .failure(error):\n                return .unknown(reason: \"subrole.\\(describe(error: error))\", path: path)\n            }\n\n            let actions: [String]\n            switch optionalActionNames(of: element) {\n            case let .success(value):\n                actions = value\n            case let .failure(error):\n                return .unknown(reason: \"actions.\\(describe(error: error))\", path: path)\n            }\n\n            path.append(accessibilityPathEntry(role: role, subrole: subrole, actions: actions))\n\n            if let role, Self.webContentAccessibilityRoles.contains(role) {\n                isInsideWebContent = true\n            }\n\n            // Once we have entered web content, ignore higher-level browser chrome ancestors\n            // like tab groups or toolbars. Safari and Chromium often expose those above the\n            // page content, and treating them as excluded chrome would block autoscroll on\n            // normal page clicks.\n            if !isInsideWebContent,\n               isExcludedActivationElement(role: role, subrole: subrole) {\n                return .excludedChrome(path: path)\n            }\n\n            if Self.isPressableActivationElement(role: role, actions: actions) {\n                return .pressable(path: path)\n            }\n\n            switch optionalElementValue(of: kAXParentAttribute as CFString, on: element) {\n            case let .success(value):\n                currentElement = value\n            case let .failure(error):\n                return .unknown(reason: \"parent.\\(describe(error: error))\", path: path)\n            }\n        }\n\n        return .unknown(reason: \"depthLimit\", path: path)\n    }\n\n    private func isExcludedActivationElement(role: String?, subrole: String?) -> Bool {\n        if let role, Self.excludedAccessibilityRoles.contains(role) {\n            return true\n        }\n\n        if let subrole, Self.excludedAccessibilitySubroles.contains(subrole) {\n            return true\n        }\n\n        return false\n    }\n\n    static func isPressableActivationElement(role: String?, actions: [String]) -> Bool {\n        guard let role,\n              pressableAccessibilityRoles.contains(role) else {\n            return false\n        }\n\n        if role == \"AXLink\" {\n            return true\n        }\n\n        return actions.contains(kAXPressAction as String)\n    }\n\n    private func requiredStringValue(\n        of attribute: CFString,\n        on element: AXUIElement\n    ) -> AccessibilityQueryResult<String?> {\n        var value: CFTypeRef?\n        let error = AXUIElementCopyAttributeValue(element, attribute, &value)\n        guard error == .success else {\n            return .failure(error)\n        }\n\n        return .success(value as? String)\n    }\n\n    private func optionalStringValue(\n        of attribute: CFString,\n        on element: AXUIElement\n    ) -> AccessibilityQueryResult<String?> {\n        var value: CFTypeRef?\n        let error = AXUIElementCopyAttributeValue(element, attribute, &value)\n        switch error {\n        case .success:\n            return .success(value as? String)\n        case .noValue, .attributeUnsupported:\n            return .success(nil)\n        default:\n            return .failure(error)\n        }\n    }\n\n    private func optionalElementValue(\n        of attribute: CFString,\n        on element: AXUIElement\n    ) -> AccessibilityQueryResult<AXUIElement?> {\n        var value: CFTypeRef?\n        let error = AXUIElementCopyAttributeValue(element, attribute, &value)\n        switch error {\n        case .success:\n            return .success(value as! AXUIElement?)\n        case .noValue, .attributeUnsupported:\n            return .success(nil)\n        default:\n            return .failure(error)\n        }\n    }\n\n    private func optionalActionNames(of element: AXUIElement) -> AccessibilityQueryResult<[String]> {\n        var actions: CFArray?\n        let error = AXUIElementCopyActionNames(element, &actions)\n        switch error {\n        case .success:\n            return .success(actions as? [String] ?? [])\n        case .noValue, .actionUnsupported, .attributeUnsupported:\n            return .success([])\n        default:\n            return .failure(error)\n        }\n    }\n\n    private func accessibilityPathEntry(role: String?, subrole: String?, actions: [String]) -> String {\n        let roleDescription = role ?? \"?\"\n        let subroleDescription = subrole.map { \"/\\($0)\" } ?? \"\"\n        let pressDescription = actions.contains(kAXPressAction as String) ? \"[press]\" : \"\"\n        return \"\\(roleDescription)\\(subroleDescription)\\(pressDescription)\"\n    }\n\n    private func describe(error: AXError) -> String {\n        switch error {\n        case .success:\n            \"success\"\n        case .failure:\n            \"failure\"\n        case .illegalArgument:\n            \"illegalArgument\"\n        case .invalidUIElement:\n            \"invalidUIElement\"\n        case .invalidUIElementObserver:\n            \"invalidUIElementObserver\"\n        case .cannotComplete:\n            \"cannotComplete\"\n        case .attributeUnsupported:\n            \"attributeUnsupported\"\n        case .actionUnsupported:\n            \"actionUnsupported\"\n        case .notificationUnsupported:\n            \"notificationUnsupported\"\n        case .notImplemented:\n            \"notImplemented\"\n        case .notificationAlreadyRegistered:\n            \"notificationAlreadyRegistered\"\n        case .notificationNotRegistered:\n            \"notificationNotRegistered\"\n        case .apiDisabled:\n            \"apiDisabled\"\n        case .noValue:\n            \"noValue\"\n        case .parameterizedAttributeUnsupported:\n            \"parameterizedAttributeUnsupported\"\n        case .notEnoughPrecision:\n            \"notEnoughPrecision\"\n        @unknown default:\n            \"unknown(\\(error.rawValue))\"\n        }\n    }\n\n    private func logAccessibilityHit(initial: ActivationProbe, resolved: ActivationProbe) {\n        let initialPointDescription = String(format: \"(%.1f, %.1f)\", initial.point.x, initial.point.y)\n        let resolvedPointDescription = String(format: \"(%.1f, %.1f)\", resolved.point.x, resolved.point.y)\n        let initialPathDescription = initial.hit.path.isEmpty ? \"-\" : initial.hit.path.joined(separator: \" -> \")\n        let resolvedPathDescription = resolved.hit.path.isEmpty ? \"-\" : resolved.hit.path.joined(separator: \" -> \")\n\n        if initial.hit.summary == resolved.hit.summary,\n           initial.hit.path == resolved.hit.path,\n           initial.point == resolved.point {\n            os_log(\n                \"Auto scroll AX hit result=%{public}@ point=%{public}@ path=%{public}@\",\n                log: Self.log,\n                type: .info,\n                resolved.hit.summary,\n                resolvedPointDescription,\n                resolvedPathDescription\n            )\n            return\n        }\n\n        os_log(\n            \"Auto scroll AX hit initial=%{public}@ initialPoint=%{public}@ initialPath=%{public}@ resolved=%{public}@ resolvedPoint=%{public}@ resolvedPath=%{public}@\",\n            log: Self.log,\n            type: .info,\n            initial.hit.summary,\n            initialPointDescription,\n            initialPathDescription,\n            resolved.hit.summary,\n            resolvedPointDescription,\n            resolvedPathDescription\n        )\n    }\n\n    private func postDeferredNativeClick(from downEvent: CGEvent) {\n        guard let eventButton = MouseEventView(downEvent).mouseButton else {\n            return\n        }\n\n        let location = downEvent.location\n        let flags = downEvent.flags\n\n        guard let mouseDownEvent = CGEvent(\n            mouseEventSource: nil,\n            mouseType: eventButton.fixedCGEventType(of: .leftMouseDown),\n            mouseCursorPosition: location,\n            mouseButton: eventButton\n        ) else {\n            return\n        }\n\n        guard let mouseUpEvent = CGEvent(\n            mouseEventSource: nil,\n            mouseType: eventButton.fixedCGEventType(of: .leftMouseUp),\n            mouseCursorPosition: location,\n            mouseButton: eventButton\n        ) else {\n            return\n        }\n\n        mouseDownEvent.flags = flags\n        mouseUpEvent.flags = flags\n        mouseDownEvent.post(tap: .cgSessionEventTap)\n        mouseUpEvent.post(tap: .cgSessionEventTap)\n    }\n}\n\nprivate enum ActivationHit {\n    case pressable(path: [String])\n    case excludedChrome(path: [String])\n    case nonPressable(path: [String])\n    case unknown(reason: String, path: [String])\n\n    var path: [String] {\n        switch self {\n        case let .pressable(path):\n            path\n        case let .excludedChrome(path):\n            path\n        case let .nonPressable(path):\n            path\n        case let .unknown(_, path):\n            path\n        }\n    }\n\n    var summary: String {\n        switch self {\n        case .pressable:\n            \"pressable\"\n        case .excludedChrome:\n            \"excludedChrome\"\n        case .nonPressable:\n            \"nonPressable\"\n        case let .unknown(reason, _):\n            \"unknown.\\(reason)\"\n        }\n    }\n\n    var suppressesAutoscroll: Bool {\n        switch self {\n        case .pressable, .excludedChrome:\n            true\n        case .nonPressable, .unknown:\n            false\n        }\n    }\n\n    var requiresAdditionalSampling: Bool {\n        switch self {\n        case .nonPressable, .unknown:\n            true\n        case .pressable, .excludedChrome:\n            false\n        }\n    }\n\n    var priority: Int {\n        switch self {\n        case .pressable, .excludedChrome:\n            3\n        case .nonPressable:\n            2\n        case .unknown:\n            1\n        }\n    }\n}\n\nprivate enum AccessibilityQueryResult<Value> {\n    case success(Value)\n    case failure(AXError)\n}\n\nprivate struct ActivationProbe {\n    let point: CGPoint\n    let hit: ActivationHit\n}\n\nextension AutoScrollTransformer: LogitechControlEventHandling {\n    func handleLogitechControlEvent(_ context: LogitechEventContext) -> Bool {\n        guard let triggerLogitechControl = trigger.button?.logitechControl,\n              context.controlIdentity.matches(triggerLogitechControl) else {\n            return false\n        }\n\n        if context.isPressed {\n            // If already active in toggle mode, deactivate on re-press\n            if case let .active(_, _, session) = state, session == .toggle {\n                guard hasToggleMode else {\n                    return true\n                }\n                deactivate()\n                return true\n            }\n\n            guard trigger.matches(modifierFlags: context.modifierFlags) else {\n                return true\n            }\n\n            activate(at: context.mouseLocation, session: activationSession)\n            return true\n        }\n\n        switch state {\n        case let .active(anchor, current, session):\n            switch session {\n            case .hold:\n                deactivate()\n            case .pendingToggleOrHold:\n                if exceedsDeadZone(from: anchor, to: current) {\n                    deactivate()\n                } else {\n                    state = .active(anchor: anchor, current: current, session: .toggle)\n                }\n            case .toggle:\n                break\n            }\n        default:\n            break\n        }\n\n        return true\n    }\n}\n\nextension AutoScrollTransformer: Deactivatable {\n    func deactivate() {\n        if isAutoscrollActive {\n            os_log(\"Auto scroll deactivated\", log: Self.log, type: .info)\n        }\n\n        state = .idle\n        suppressTriggerUp = false\n        DispatchQueue.main.async { [indicatorController] in\n            indicatorController.hide()\n        }\n\n        timer?.invalidate()\n        timer = nil\n    }\n}\n\nextension AutoScrollTransformer {\n    func matchesConfiguration(\n        trigger: Scheme.Buttons.Mapping,\n        modes: [Scheme.Buttons.AutoScroll.Mode],\n        speed: Double,\n        preserveNativeMiddleClick: Bool\n    ) -> Bool {\n        self.trigger == trigger &&\n            self.modes == modes &&\n            abs(self.speed - speed) < 0.0001 &&\n            self.preserveNativeMiddleClick == preserveNativeMiddleClick\n    }\n}\n\nprivate final class AutoScrollIndicatorWindowController {\n    private lazy var window: NSPanel = {\n        let panel = NSPanel(\n            contentRect: CGRect(origin: .zero, size: autoScrollIndicatorSize),\n            styleMask: [.borderless, .nonactivatingPanel],\n            backing: .buffered,\n            defer: false\n        )\n        panel.isOpaque = false\n        panel.backgroundColor = .clear\n        panel.hasShadow = false\n        panel.level = .statusBar\n        panel.ignoresMouseEvents = true\n        panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .stationary]\n        panel.contentView = AutoScrollIndicatorView(frame: CGRect(origin: .zero, size: autoScrollIndicatorSize))\n        return panel\n    }()\n\n    func show(at point: CGPoint) {\n        let origin = CGPoint(\n            x: point.x - autoScrollIndicatorSize.width / 2,\n            y: point.y - autoScrollIndicatorSize.height / 2\n        )\n        window.setFrame(CGRect(origin: origin, size: autoScrollIndicatorSize), display: true)\n        window.orderFrontRegardless()\n    }\n\n    func update(delta: CGVector) {\n        (window.contentView as? AutoScrollIndicatorView)?.delta = delta\n    }\n\n    func hide() {\n        window.orderOut(nil)\n    }\n}\n\nprivate final class AutoScrollIndicatorView: NSView {\n    var delta: CGVector = .zero {\n        didSet {\n            needsDisplay = true\n        }\n    }\n\n    override var isOpaque: Bool {\n        false\n    }\n\n    override func draw(_ dirtyRect: NSRect) {\n        super.draw(dirtyRect)\n\n        let bounds = bounds\n        let circleRect = bounds.insetBy(dx: 4, dy: 4)\n        let ringPath = NSBezierPath(ovalIn: circleRect)\n\n        if let context = NSGraphicsContext.current?.cgContext {\n            context.saveGState()\n            context.setShadow(\n                offset: CGSize(width: 0, height: -1),\n                blur: 10,\n                color: NSColor.black.withAlphaComponent(0.18).cgColor\n            )\n\n            let gradient = NSGradient(\n                colors: [\n                    NSColor(white: 1.0, alpha: 0.97),\n                    NSColor(white: 0.93, alpha: 0.95)\n                ]\n            )\n            gradient?.draw(in: ringPath, angle: 90)\n            context.restoreGState()\n        }\n\n        NSColor(white: 0.12, alpha: 0.48).setStroke()\n        ringPath.lineWidth = 1\n        ringPath.stroke()\n\n        let innerRingPath = NSBezierPath(ovalIn: circleRect.insetBy(dx: 1.5, dy: 1.5))\n        NSColor.white.withAlphaComponent(0.45).setStroke()\n        innerRingPath.lineWidth = 1\n        innerRingPath.stroke()\n\n        let center = CGPoint(x: bounds.midX, y: bounds.midY)\n        let horizontalIntensity = CGFloat(min(1, max(0, (abs(delta.dx) - 10) / 44)))\n        let verticalIntensity = CGFloat(min(1, max(0, (abs(delta.dy) - 10) / 44)))\n\n        drawArrow(\n            at: CGPoint(x: center.x, y: bounds.maxY - 13),\n            direction: .up,\n            intensity: delta.dy > 0 ? verticalIntensity : 0\n        )\n        drawArrow(\n            at: CGPoint(x: bounds.maxX - 13, y: center.y),\n            direction: .right,\n            intensity: delta.dx > 0 ? horizontalIntensity : 0\n        )\n        drawArrow(\n            at: CGPoint(x: center.x, y: bounds.minY + 13),\n            direction: .down,\n            intensity: delta.dy < 0 ? verticalIntensity : 0\n        )\n        drawArrow(\n            at: CGPoint(x: bounds.minX + 13, y: center.y),\n            direction: .left,\n            intensity: delta.dx < 0 ? horizontalIntensity : 0\n        )\n\n        let crosshair = NSBezierPath()\n        crosshair.move(to: CGPoint(x: center.x, y: bounds.minY + 11))\n        crosshair.line(to: CGPoint(x: center.x, y: bounds.maxY - 11))\n        crosshair.move(to: CGPoint(x: bounds.minX + 11, y: center.y))\n        crosshair.line(to: CGPoint(x: bounds.maxX - 11, y: center.y))\n        NSColor(white: 0.1, alpha: 0.14).setStroke()\n        crosshair.lineWidth = 1\n        crosshair.stroke()\n\n        let centerShadowRect = CGRect(x: center.x - 5, y: center.y - 5, width: 10, height: 10)\n        let centerShadowPath = NSBezierPath(ovalIn: centerShadowRect)\n        NSColor.black.withAlphaComponent(0.14).setFill()\n        centerShadowPath.fill()\n\n        let dotRect = CGRect(x: center.x - 4, y: center.y - 4, width: 8, height: 8)\n        let dotPath = NSBezierPath(ovalIn: dotRect)\n        NSColor(white: 0.07, alpha: 0.96).setFill()\n        dotPath.fill()\n\n        let highlightRect = CGRect(x: center.x - 1.5, y: center.y + 1, width: 3, height: 2)\n        let highlightPath = NSBezierPath(ovalIn: highlightRect)\n        NSColor.white.withAlphaComponent(0.28).setFill()\n        highlightPath.fill()\n    }\n\n    private func drawArrow(at center: CGPoint, direction: Direction, intensity: CGFloat) {\n        let path = NSBezierPath()\n\n        switch direction {\n        case .up:\n            path.move(to: CGPoint(x: center.x, y: center.y + 6))\n            path.line(to: CGPoint(x: center.x - 4.5, y: center.y - 3))\n            path.line(to: CGPoint(x: center.x + 4.5, y: center.y - 3))\n        case .right:\n            path.move(to: CGPoint(x: center.x + 6, y: center.y))\n            path.line(to: CGPoint(x: center.x - 3, y: center.y + 4.5))\n            path.line(to: CGPoint(x: center.x - 3, y: center.y - 4.5))\n        case .down:\n            path.move(to: CGPoint(x: center.x, y: center.y - 6))\n            path.line(to: CGPoint(x: center.x - 4.5, y: center.y + 3))\n            path.line(to: CGPoint(x: center.x + 4.5, y: center.y + 3))\n        case .left:\n            path.move(to: CGPoint(x: center.x - 6, y: center.y))\n            path.line(to: CGPoint(x: center.x + 3, y: center.y + 4.5))\n            path.line(to: CGPoint(x: center.x + 3, y: center.y - 4.5))\n        }\n\n        path.close()\n\n        let alpha = 0.26 + Double(intensity) * 0.68\n        NSColor(white: 0.04, alpha: alpha).setFill()\n        path.fill()\n\n        NSColor.white.withAlphaComponent(0.18 + Double(intensity) * 0.12).setStroke()\n        path.lineWidth = 0.7\n        path.stroke()\n    }\n\n    private enum Direction {\n        case up\n        case right\n        case down\n        case left\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/ButtonActionsTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport DockKit\nimport Foundation\nimport GestureKit\nimport KeyKit\nimport os.log\n\nclass ButtonActionsTransformer {\n    static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"ButtonActions\")\n\n    let mappings: [Scheme.Buttons.Mapping]\n    let universalBackForward: Scheme.Buttons.UniversalBackForward?\n\n    private enum TimerSlot {\n        case standard\n        case logitech\n    }\n\n    var repeatTimer: EventThreadTimer?\n    private var logitechRepeatTimer: EventThreadTimer?\n    private var heldKeysByButton = [Scheme.Buttons.Mapping.Button: [Key]]()\n\n    private static let defaultKeySimulator = KeySimulator()\n    let keySimulator: KeySimulating\n\n    init(\n        mappings: [Scheme.Buttons.Mapping],\n        universalBackForward: Scheme.Buttons.UniversalBackForward? = nil,\n        keySimulator: KeySimulating? = nil\n    ) {\n        self.mappings = mappings\n        self.universalBackForward = universalBackForward\n        self.keySimulator = keySimulator ?? Self.defaultKeySimulator\n    }\n\n    private func timer(for slot: TimerSlot) -> EventThreadTimer? {\n        switch slot {\n        case .standard: repeatTimer\n        case .logitech: logitechRepeatTimer\n        }\n    }\n\n    private func setTimer(_ slot: TimerSlot, _ timer: EventThreadTimer?) {\n        switch slot {\n        case .standard: repeatTimer = timer\n        case .logitech: logitechRepeatTimer = timer\n        }\n    }\n}\n\nextension ButtonActionsTransformer: EventTransformer, LogitechControlEventHandling {\n    var mouseDownEventTypes: [CGEventType] {\n        [.leftMouseDown, .rightMouseDown, .otherMouseDown]\n    }\n\n    var mouseUpEventTypes: [CGEventType] {\n        [.leftMouseUp, .rightMouseUp, .otherMouseUp]\n    }\n\n    var mouseDraggedEventTypes: [CGEventType] {\n        [.leftMouseDragged, .rightMouseDragged, .otherMouseDragged]\n    }\n\n    var scrollWheelsEventTypes: [CGEventType] {\n        [.scrollWheel]\n    }\n\n    var keyTypes: [CGEventType] {\n        [.keyDown, .keyUp]\n    }\n\n    var allEventTypesOfInterest: [CGEventType] {\n        [mouseDownEventTypes, mouseUpEventTypes, mouseDraggedEventTypes, scrollWheelsEventTypes, keyTypes]\n            .flatMap(\\.self)\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard allEventTypesOfInterest.contains(event.type) else {\n            return event\n        }\n\n        if event.isGestureCleanupRelease {\n            return event\n        }\n\n        guard !SettingsState.shared.recording else {\n            return event\n        }\n\n        if keyTypes.contains(event.type), let newFlags = keySimulator.modifiedCGEventFlags(of: event) {\n            os_log(\n                \"Update CGEventFlags from %{public}llu to %{public}llu\",\n                log: Self.log,\n                type: .info,\n                event.flags.rawValue,\n                newFlags.rawValue\n            )\n            event.flags = newFlags\n        }\n\n        // FIXME: Temporary fix for \"repeat on hold\"\n        if !mouseDraggedEventTypes.contains(event.type) {\n            repeatTimer?.invalidate()\n            repeatTimer = nil\n        }\n\n        guard let mapping = findMapping(of: event) else {\n            return event\n        }\n\n        guard let action = mapping.action else {\n            return event\n        }\n\n        if case .arg0(.auto) = action {\n            return event\n        }\n\n        if event.type == .scrollWheel {\n            queueActions(event: event.copy(), action: action)\n        } else {\n            if handleKeyPressHold(event: event, mapping: mapping, action: action) {\n                return nil\n            }\n\n            // FIXME: `NSEvent.keyRepeatDelay` and `NSEvent.keyRepeatInterval` are not kept up to date\n            // TODO: Support override `repeatDelay` and `repeatInterval`\n            let keyRepeatDelay = mapping.repeat == true ? KeyboardSettingsSnapshot.shared.keyRepeatDelay : 0\n            let keyRepeatInterval = mapping.repeat == true ? KeyboardSettingsSnapshot.shared.keyRepeatInterval : 0\n            let keyRepeatEnabled = keyRepeatDelay > 0 && keyRepeatInterval > 0\n\n            if !keyRepeatEnabled {\n                if handleButtonSwaps(event: event, action: action) {\n                    return event\n                }\n            }\n\n            // Actions are executed when button is down if key repeat is enabled; otherwise, actions are\n            // executed when button is up.\n            let eventsOfInterest = keyRepeatEnabled ? mouseDownEventTypes : mouseUpEventTypes\n\n            guard eventsOfInterest.contains(event.type) else {\n                return nil\n            }\n\n            queueActions(\n                event: event.copy(),\n                action: action,\n                keyRepeatEnabled: keyRepeatEnabled,\n                keyRepeatDelay: keyRepeatDelay,\n                keyRepeatInterval: keyRepeatInterval\n            )\n        }\n\n        return nil\n    }\n\n    private func findMapping(of event: CGEvent) -> Scheme.Buttons.Mapping? {\n        mappings.last { $0.match(with: event) }\n    }\n\n    /// Find the best Logitech mapping for the given control event context (read-only, thread-safe).\n    func findLogitechMapping(\n        for context: LogitechEventContext\n    ) -> (mapping: Scheme.Buttons.Mapping, action: Scheme.Buttons.Mapping.Action)? {\n        guard !SettingsState.shared.recording else {\n            return nil\n        }\n\n        let matchingMappings = mappings.filter { mapping in\n            guard let logiButton = mapping.button?.logitechControl,\n                  context.controlIdentity.matches(logiButton) else {\n                return false\n            }\n\n            return mapping.matches(modifierFlags: context.modifierFlags)\n        }\n\n        guard let mapping = matchingMappings.enumerated()\n            .max(by: { lhs, rhs in\n                let lhsSpecificity = lhs.element.button?.logitechControl?.specificityScore ?? 0\n                let rhsSpecificity = rhs.element.button?.logitechControl?.specificityScore ?? 0\n\n                if lhsSpecificity == rhsSpecificity {\n                    return lhs.offset < rhs.offset\n                }\n\n                return lhsSpecificity < rhsSpecificity\n            })?.element,\n            let action = mapping.action else {\n            return nil\n        }\n\n        if case .arg0(.auto) = action {\n            return nil\n        }\n\n        return (mapping, action)\n    }\n\n    func handleLogitechControlEvent(_ context: LogitechEventContext) -> Bool {\n        guard let (mapping, action) = findLogitechMapping(for: context) else {\n            return false\n        }\n\n        if handleLogitechKeyPressHold(mapping: mapping, action: action, context: context) {\n            return true\n        }\n\n        logitechRepeatTimer?.invalidate()\n        logitechRepeatTimer = nil\n\n        let keyRepeatDelay = mapping.repeat == true ? KeyboardSettingsSnapshot.shared.keyRepeatDelay : 0\n        let keyRepeatInterval = mapping.repeat == true ? KeyboardSettingsSnapshot.shared.keyRepeatInterval : 0\n        let keyRepeatEnabled = keyRepeatDelay > 0 && keyRepeatInterval > 0\n        let shouldExecute = keyRepeatEnabled ? context.isPressed : !context.isPressed\n\n        guard shouldExecute else {\n            return true\n        }\n\n        queueLogitechActions(\n            event: nil,\n            action: action,\n            targetBundleIdentifier: context.pid?.bundleIdentifier,\n            keyRepeatEnabled: keyRepeatEnabled,\n            keyRepeatDelay: keyRepeatDelay,\n            keyRepeatInterval: keyRepeatInterval\n        )\n        return true\n    }\n\n    private func shouldHoldKeys(\n        for mapping: Scheme.Buttons.Mapping,\n        action: Scheme.Buttons.Mapping.Action\n    ) -> Bool {\n        guard case let .arg1(.keyPress(keys)) = action else {\n            return false\n        }\n\n        return mapping.hold == true || keys.allSatisfy(\\.isModifier)\n    }\n\n    private func handleLogitechKeyPressHold(\n        mapping: Scheme.Buttons.Mapping,\n        action: Scheme.Buttons.Mapping.Action,\n        context: LogitechEventContext\n    ) -> Bool {\n        guard let button = mapping.button,\n              shouldHoldKeys(for: mapping, action: action),\n              case let .arg1(.keyPress(keys)) = action else {\n            return false\n        }\n\n        if context.isPressed {\n            pressAndStoreHeldKeys(keys, for: button)\n        } else {\n            releaseHeldKeys(for: button, fallbackKeys: keys)\n        }\n\n        return true\n    }\n\n    private func queueActions(\n        event: CGEvent?,\n        action: Scheme.Buttons.Mapping.Action,\n        keyRepeatEnabled: Bool = false,\n        keyRepeatDelay: TimeInterval = 0,\n        keyRepeatInterval: TimeInterval = 0\n    ) {\n        let targetBundleIdentifier = event.flatMap { MouseEventView($0).targetPid?.bundleIdentifier }\n        scheduleRepeatActions(\n            slot: .standard,\n            action: action,\n            targetBundleIdentifier: targetBundleIdentifier,\n            keyRepeatEnabled: keyRepeatEnabled,\n            keyRepeatDelay: keyRepeatDelay,\n            keyRepeatInterval: keyRepeatInterval\n        )\n    }\n\n    private func queueLogitechActions(\n        event _: CGEvent?,\n        action: Scheme.Buttons.Mapping.Action,\n        targetBundleIdentifier: String?,\n        keyRepeatEnabled: Bool = false,\n        keyRepeatDelay: TimeInterval = 0,\n        keyRepeatInterval: TimeInterval = 0\n    ) {\n        scheduleRepeatActions(\n            slot: .logitech,\n            action: action,\n            targetBundleIdentifier: targetBundleIdentifier,\n            keyRepeatEnabled: keyRepeatEnabled,\n            keyRepeatDelay: keyRepeatDelay,\n            keyRepeatInterval: keyRepeatInterval\n        )\n    }\n\n    private func scheduleRepeatActions(\n        slot: TimerSlot,\n        action: Scheme.Buttons.Mapping.Action,\n        targetBundleIdentifier: String?,\n        keyRepeatEnabled: Bool,\n        keyRepeatDelay: TimeInterval,\n        keyRepeatInterval: TimeInterval\n    ) {\n        DispatchQueue.main.async { [self] in\n            executeIgnoreErrors(action: action, targetBundleIdentifier: targetBundleIdentifier)\n        }\n\n        guard keyRepeatEnabled else {\n            return\n        }\n\n        setTimer(slot, EventThread.shared.scheduleTimer(\n            interval: keyRepeatDelay,\n            repeats: false\n        ) { [weak self] in\n            guard let self else {\n                return\n            }\n\n            DispatchQueue.main.async { [self] in\n                self.executeIgnoreErrors(action: action, targetBundleIdentifier: targetBundleIdentifier)\n            }\n\n            self.setTimer(slot, EventThread.shared.scheduleTimer(\n                interval: keyRepeatInterval,\n                repeats: true\n            ) { [weak self] in\n                guard let self else {\n                    return\n                }\n                DispatchQueue.main.async { [self] in\n                    self.executeIgnoreErrors(action: action, targetBundleIdentifier: targetBundleIdentifier)\n                }\n            })\n        })\n    }\n\n    private func executeIgnoreErrors(\n        action: Scheme.Buttons.Mapping.Action,\n        targetBundleIdentifier: String?\n    ) {\n        do {\n            os_log(\n                \"Execute action: %{public}@\",\n                log: Self.log,\n                type: .info,\n                String(describing: action)\n            )\n\n            try execute(action: action, targetBundleIdentifier: targetBundleIdentifier)\n        } catch {\n            os_log(\n                \"Failed to execute: %{public}@: %{public}@\",\n                log: Self.log,\n                type: .error,\n                String(describing: action),\n                String(describing: error)\n            )\n        }\n    }\n\n    // swiftlint:disable:next cyclomatic_complexity\n    private func execute(\n        action: Scheme.Buttons.Mapping.Action,\n        targetBundleIdentifier: String?\n    ) throws {\n        switch action {\n        case .arg0(.none), .arg0(.auto):\n            return\n\n        case .arg0(.missionControlSpaceLeft):\n            try postSymbolicHotKey(.spaceLeft)\n\n        case .arg0(.missionControlSpaceRight):\n            try postSymbolicHotKey(.spaceRight)\n\n        case .arg0(.missionControl):\n            missionControl()\n\n        case .arg0(.appExpose):\n            appExpose()\n\n        case .arg0(.launchpad):\n            launchpad()\n\n        case .arg0(.showDesktop):\n            showDesktop()\n\n        case .arg0(.lookUpAndDataDetectors):\n            try postSymbolicHotKey(.lookUpWordInDictionary)\n\n        case .arg0(.smartZoom):\n            GestureEvent(zoomToggleSource: nil)?.post(tap: .cgSessionEventTap)\n\n        case .arg0(.displayBrightnessUp):\n            postSystemDefinedKey(.brightnessUp)\n\n        case .arg0(.displayBrightnessDown):\n            postSystemDefinedKey(.brightnessDown)\n\n        case .arg0(.mediaVolumeUp):\n            postSystemDefinedKey(.soundUp)\n\n        case .arg0(.mediaVolumeDown):\n            postSystemDefinedKey(.soundDown)\n\n        case .arg0(.mediaMute):\n            postSystemDefinedKey(.mute)\n\n        case .arg0(.mediaPlayPause):\n            postSystemDefinedKey(.play)\n\n        case .arg0(.mediaNext):\n            postSystemDefinedKey(.next)\n\n        case .arg0(.mediaPrevious):\n            postSystemDefinedKey(.previous)\n\n        case .arg0(.mediaFastForward):\n            postSystemDefinedKey(.fast)\n\n        case .arg0(.mediaRewind):\n            postSystemDefinedKey(.rewind)\n\n        case .arg0(.keyboardBrightnessUp):\n            postSystemDefinedKey(.illuminationUp)\n\n        case .arg0(.keyboardBrightnessDown):\n            postSystemDefinedKey(.illuminationDown)\n\n        case .arg0(.mouseWheelScrollUp):\n            postScrollEvent(horizontal: 0, vertical: 3)\n\n        case .arg0(.mouseWheelScrollDown):\n            postScrollEvent(horizontal: 0, vertical: -3)\n\n        case .arg0(.mouseWheelScrollLeft):\n            postScrollEvent(horizontal: 3, vertical: 0)\n\n        case .arg0(.mouseWheelScrollRight):\n            postScrollEvent(horizontal: -3, vertical: 0)\n\n        case .arg0(.mouseButtonLeft):\n            postClickEvent(mouseButton: .left)\n\n        case .arg0(.mouseButtonLeftDouble):\n            postClickEvent(mouseButton: .left)\n            postClickEvent(mouseButton: .left, clickState: 2)\n\n        case .arg0(.mouseButtonMiddle):\n            postClickEvent(mouseButton: .center)\n\n        case .arg0(.mouseButtonRight):\n            postClickEvent(mouseButton: .right)\n\n        case .arg0(.mouseButtonBack):\n            postMouseButtonAction(mouseButton: .back, targetBundleIdentifier: targetBundleIdentifier)\n\n        case .arg0(.mouseButtonForward):\n            postMouseButtonAction(mouseButton: .forward, targetBundleIdentifier: targetBundleIdentifier)\n\n        case let .arg1(.run(command)):\n            let task = Process()\n            task.launchPath = \"/bin/bash\"\n            task.arguments = [\"-c\", command]\n            task.launch()\n\n        case let .arg1(.mouseWheelScrollUp(distance)):\n            postScrollEvent(direction: .up, distance: distance)\n\n        case let .arg1(.mouseWheelScrollDown(distance)):\n            postScrollEvent(direction: .down, distance: distance)\n\n        case let .arg1(.mouseWheelScrollLeft(distance)):\n            postScrollEvent(direction: .left, distance: distance)\n\n        case let .arg1(.mouseWheelScrollRight(distance)):\n            postScrollEvent(direction: .right, distance: distance)\n\n        case let .arg1(.keyPress(keys)):\n            try keySimulator.press(keys: keys, tap: .cgSessionEventTap)\n            keySimulator.reset()\n        }\n    }\n\n    private func postMouseButtonAction(\n        mouseButton: CGMouseButton,\n        targetBundleIdentifier: String?\n    ) {\n        guard !UniversalBackForwardTransformer.postNavigationSwipeIfNeeded(\n            for: mouseButton,\n            universalBackForward: universalBackForward,\n            targetBundleIdentifier: targetBundleIdentifier\n        ) else {\n            return\n        }\n\n        postClickEvent(mouseButton: mouseButton)\n    }\n\n    private func postScrollEvent(horizontal: Int32, vertical: Int32) {\n        guard let event = CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: vertical,\n            wheel2: horizontal,\n            wheel3: 0\n        ) else {\n            return\n        }\n\n        event.flags = []\n        event.post(tap: .cgSessionEventTap)\n    }\n\n    private func postContinuousScrollEvent(horizontal: Double, vertical: Double) {\n        guard let event = CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .pixel,\n            wheelCount: 2,\n            wheel1: 0,\n            wheel2: 0,\n            wheel3: 0\n        ) else {\n            return\n        }\n\n        event.setDoubleValueField(.scrollWheelEventPointDeltaAxis1, value: vertical)\n        event.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis1, value: vertical)\n        event.setDoubleValueField(.scrollWheelEventPointDeltaAxis2, value: horizontal)\n        event.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis2, value: horizontal)\n\n        event.flags = []\n        event.post(tap: .cgSessionEventTap)\n    }\n\n    private enum ScrollEventDirection {\n        case up, down, left, right\n    }\n\n    private func postScrollEvent(\n        direction: ScrollEventDirection,\n        distance: Scheme.Scrolling.Distance\n    ) {\n        switch distance {\n        case .auto:\n            switch direction {\n            case .up:\n                postScrollEvent(horizontal: 0, vertical: 3)\n            case .down:\n                postScrollEvent(horizontal: 0, vertical: -3)\n            case .left:\n                postScrollEvent(horizontal: 3, vertical: 0)\n            case .right:\n                postScrollEvent(horizontal: -3, vertical: 0)\n            }\n\n        case let .line(value):\n            let value = Int32(value)\n\n            switch direction {\n            case .up:\n                postScrollEvent(horizontal: 0, vertical: value)\n            case .down:\n                postScrollEvent(horizontal: 0, vertical: -value)\n            case .left:\n                postScrollEvent(horizontal: value, vertical: 0)\n            case .right:\n                postScrollEvent(horizontal: -value, vertical: 0)\n            }\n\n        case let .pixel(value):\n            let value = value.asTruncatedDouble\n\n            switch direction {\n            case .up:\n                postContinuousScrollEvent(horizontal: 0, vertical: value)\n            case .down:\n                postContinuousScrollEvent(horizontal: 0, vertical: -value)\n            case .left:\n                postContinuousScrollEvent(horizontal: value, vertical: 0)\n            case .right:\n                postContinuousScrollEvent(horizontal: -value, vertical: 0)\n            }\n        }\n    }\n\n    private func handleButtonSwaps(event: CGEvent, action: Scheme.Buttons.Mapping.Action) -> Bool {\n        guard [mouseDownEventTypes, mouseUpEventTypes, mouseDraggedEventTypes]\n            .flatMap(\\.self)\n            .contains(event.type)\n        else {\n            return false\n        }\n\n        let mouseEventView = MouseEventView(event)\n\n        switch action {\n        case .arg0(.mouseButtonLeft):\n            mouseEventView.modifierFlags = []\n            mouseEventView.mouseButton = .left\n        case .arg0(.mouseButtonMiddle):\n            mouseEventView.modifierFlags = []\n            mouseEventView.mouseButton = .center\n        case .arg0(.mouseButtonRight):\n            mouseEventView.modifierFlags = []\n            mouseEventView.mouseButton = .right\n        case .arg0(.mouseButtonBack):\n            mouseEventView.modifierFlags = []\n            mouseEventView.mouseButton = .back\n        case .arg0(.mouseButtonForward):\n            mouseEventView.modifierFlags = []\n            mouseEventView.mouseButton = .forward\n        default:\n            return false\n        }\n\n        os_log(\n            \"Set mouse button to %{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: mouseEventView.mouseButtonDescription)\n        )\n\n        return true\n    }\n\n    private func handleKeyPressHold(\n        event: CGEvent,\n        mapping: Scheme.Buttons.Mapping,\n        action: Scheme.Buttons.Mapping.Action\n    ) -> Bool {\n        guard let button = mapping.button,\n              [mouseDownEventTypes, mouseUpEventTypes, mouseDraggedEventTypes]\n              .flatMap(\\.self)\n              .contains(event.type),\n              shouldHoldKeys(for: mapping, action: action),\n              case let .arg1(.keyPress(keys)) = action else {\n            return false\n        }\n\n        if mouseDraggedEventTypes.contains(event.type) {\n            return true\n        }\n\n        if mouseDownEventTypes.contains(event.type) {\n            pressAndStoreHeldKeys(keys, for: button)\n            return true\n        }\n\n        if mouseUpEventTypes.contains(event.type) {\n            releaseHeldKeys(for: button, fallbackKeys: keys)\n            return true\n        }\n\n        return false\n    }\n\n    private func pressAndStoreHeldKeys(_ keys: [Key], for button: Scheme.Buttons.Mapping.Button) {\n        // Treat the down→up cycle as atomic: once a button is tracked, ignore any subsequent\n        // pressed=true reports until release. Otherwise a stuttering pressed=true that resolves\n        // to a different mapping (e.g. modifier flags changed mid-hold and matched another rule)\n        // would overwrite `heldKeysByButton[button]` without releasing the originally pressed\n        // keys, leaving them stuck until something else clears them.\n        if heldKeysByButton[button] != nil {\n            return\n        }\n\n        heldKeysByButton[button] = keys\n\n        os_log(\"Down keys: %{public}@\", log: Self.log, type: .info, String(describing: keys))\n        try? keySimulator.down(keys: keys, tap: .cgSessionEventTap)\n    }\n\n    private func releaseHeldKeys(for button: Scheme.Buttons.Mapping.Button, fallbackKeys: [Key]) {\n        let keys = heldKeysByButton.removeValue(forKey: button) ?? fallbackKeys\n\n        os_log(\"Up keys: %{public}@\", log: Self.log, type: .info, String(describing: keys))\n        try? keySimulator.up(keys: keys.reversed(), tap: .cgSessionEventTap)\n\n        // Only clear KeySimulator's tracked modifier flags once nothing is held; otherwise an\n        // overlapping hold on another button would have its modifier state forgotten, which then\n        // leaks into the next synthetic event we emit (event.flags would be missing the still-held\n        // modifier and the OS would interpret it as released).\n        if heldKeysByButton.isEmpty {\n            keySimulator.reset()\n        }\n    }\n\n    private func postClickEvent(mouseButton: CGMouseButton, clickState: Int64? = nil) {\n        guard let location = CGEvent(source: nil)?.location else {\n            return\n        }\n\n        guard let mouseDownEvent = CGEvent(\n            mouseEventSource: nil,\n            mouseType: mouseButton.fixedCGEventType(of: .leftMouseDown),\n            mouseCursorPosition: location,\n            mouseButton: mouseButton\n        ) else {\n            return\n        }\n        guard let mouseUpEvent = CGEvent(\n            mouseEventSource: nil,\n            mouseType: mouseButton.fixedCGEventType(of: .leftMouseUp),\n            mouseCursorPosition: location,\n            mouseButton: mouseButton\n        ) else {\n            return\n        }\n\n        if let clickState {\n            mouseDownEvent.setIntegerValueField(.mouseEventClickState, value: clickState)\n            mouseUpEvent.setIntegerValueField(.mouseEventClickState, value: clickState)\n        }\n\n        mouseDownEvent.post(tap: .cgSessionEventTap)\n        mouseUpEvent.post(tap: .cgSessionEventTap)\n    }\n}\n\nextension ButtonActionsTransformer: Deactivatable {\n    func deactivate() {\n        if let repeatTimer {\n            os_log(\"ButtonActionsTransformer is inactive, invalidate the repeat timer\", log: Self.log, type: .info)\n            repeatTimer.invalidate()\n            self.repeatTimer = nil\n        }\n\n        if let logitechRepeatTimer {\n            logitechRepeatTimer.invalidate()\n            self.logitechRepeatTimer = nil\n        }\n\n        let heldKeys = heldKeysByButton.values\n        heldKeysByButton.removeAll()\n        for keys in heldKeys {\n            try? keySimulator.up(keys: keys.reversed(), tap: .cgSessionEventTap)\n        }\n        keySimulator.reset()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/ClickDebouncingTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nclass ClickDebouncingTransformer: EventTransformer {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"ClickDebouncing\")\n\n    private let button: CGMouseButton\n    private let timeout: TimeInterval\n    private let resetTimerOnMouseUp: Bool\n\n    init(for button: CGMouseButton, timeout: TimeInterval, resetTimerOnMouseUp: Bool) {\n        self.button = button\n        self.timeout = timeout\n        self.resetTimerOnMouseUp = resetTimerOnMouseUp\n    }\n\n    private var mouseDownEventType: CGEventType {\n        button.fixedCGEventType(of: .leftMouseDown)\n    }\n\n    private var mouseUpEventType: CGEventType {\n        button.fixedCGEventType(of: .leftMouseUp)\n    }\n\n    private var lastClickedAtInNanoseconds: UInt64 = 0\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard [mouseDownEventType, mouseUpEventType].contains(event.type) else {\n            return event\n        }\n        let mouseEventView = MouseEventView(event)\n        guard mouseEventView.mouseButton == button else {\n            return event\n        }\n\n        switch event.type {\n        case mouseDownEventType:\n            let intervalSinceLastClick = intervalSinceLastClick\n            touchLastClickedAt()\n            if intervalSinceLastClick <= timeout {\n                os_log(\n                    \"Mouse down ignored because interval since last click %{public}f <= %{public}f\",\n                    log: Self.log,\n                    type: .info,\n                    intervalSinceLastClick,\n                    timeout\n                )\n                return nil\n            }\n            return event\n        case mouseUpEventType:\n            if resetTimerOnMouseUp {\n                touchLastClickedAt()\n            }\n            return event\n        default:\n            break\n        }\n\n        return event\n    }\n\n    private func touchLastClickedAt() {\n        lastClickedAtInNanoseconds = DispatchTime.now().uptimeNanoseconds\n    }\n\n    private var intervalSinceLastClick: TimeInterval {\n        let nanosecondsPerSecond = 1e9\n        return Double(DispatchTime.now().uptimeNanoseconds - lastClickedAtInNanoseconds) / nanosecondsPerSecond\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/EventTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport LRUCache\nimport os.log\n\nprotocol EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent?\n}\n\nprotocol LogitechControlEventHandling {\n    func handleLogitechControlEvent(_ context: LogitechEventContext) -> Bool\n}\n\nextension [EventTransformer]: EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent? {\n        var event: CGEvent? = event\n\n        for eventTransformer in self {\n            event = event.flatMap { eventTransformer.transform($0) }\n        }\n\n        return event\n    }\n}\n\nextension [EventTransformer]: LogitechControlEventHandling {\n    func handleLogitechControlEvent(_ context: LogitechEventContext) -> Bool {\n        contains { eventTransformer in\n            (eventTransformer as? LogitechControlEventHandling)?.handleLogitechControlEvent(context) == true\n        }\n    }\n}\n\nprotocol Deactivatable {\n    func deactivate()\n    func reactivate()\n}\n\nextension Deactivatable {\n    func deactivate() {}\n    func reactivate() {}\n}\n\nextension [EventTransformer]: Deactivatable {\n    func deactivate() {\n        for eventTransformer in self {\n            if let eventTransformer = eventTransformer as? Deactivatable {\n                eventTransformer.deactivate()\n            }\n        }\n    }\n\n    func reactivate() {\n        for eventTransformer in self {\n            if let eventTransformer = eventTransformer as? Deactivatable {\n                eventTransformer.reactivate()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/EventTransformerManager.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Defaults\nimport Foundation\nimport LRUCache\nimport os.log\n\nclass EventTransformerManager {\n    static let shared = EventTransformerManager()\n    static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"EventTransformerManager\")\n\n    @Default(.bypassEventsFromOtherApplications) var bypassEventsFromOtherApplications\n\n    private var eventTransformerCache = LRUCache<CacheKey, EventTransformer>(countLimit: 16)\n    private var activeCacheKey: CacheKey?\n    private var sharedAutoScrollTransformer: AutoScrollTransformer?\n\n    struct CacheKey: Hashable {\n        var deviceMatcher: DeviceMatcher?\n        var pid: pid_t?\n        var screen: String?\n    }\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    init() {\n        ConfigurationState.shared\n            .$configuration\n            .removeDuplicates()\n            .sink { [weak self] _ in\n                guard let self else {\n                    return\n                }\n\n                if EventThread.shared.performAndWait({ self.resetState() }) == nil {\n                    self.resetState()\n                }\n            }\n            .store(in: &subscriptions)\n    }\n\n    /// Called from `EventThread.onWillStop` on the event thread.\n    func resetForRestart() {\n        resetState()\n    }\n\n    private let sourceBundleIdentifierBypassSet: Set<String> = [\n        \"cc.ffitch.shottr\"\n    ]\n\n    func get(\n        withCGEvent cgEvent: CGEvent,\n        withSourcePid sourcePid: pid_t?,\n        withTargetPid targetPid: pid_t?,\n        withMouseLocationPid mouseLocationPid: pid_t?,\n        withDisplay display: String?\n    ) -> EventTransformer {\n        if EventThread.shared.isCurrent {\n            return getOnCurrentThread(\n                withCGEvent: cgEvent,\n                withSourcePid: sourcePid,\n                withTargetPid: targetPid,\n                withMouseLocationPid: mouseLocationPid,\n                withDisplay: display\n            )\n        }\n\n        if let transformer = EventThread.shared.performAndWait({\n            self.getOnCurrentThread(\n                withCGEvent: cgEvent,\n                withSourcePid: sourcePid,\n                withTargetPid: targetPid,\n                withMouseLocationPid: mouseLocationPid,\n                withDisplay: display\n            )\n        }) {\n            return transformer\n        }\n\n        return getOnCurrentThread(\n            withCGEvent: cgEvent,\n            withSourcePid: sourcePid,\n            withTargetPid: targetPid,\n            withMouseLocationPid: mouseLocationPid,\n            withDisplay: display\n        )\n    }\n\n    private func getOnCurrentThread(\n        withCGEvent cgEvent: CGEvent,\n        withSourcePid sourcePid: pid_t?,\n        withTargetPid targetPid: pid_t?,\n        withMouseLocationPid mouseLocationPid: pid_t?,\n        withDisplay display: String?\n    ) -> EventTransformer {\n        if sourcePid != nil, bypassEventsFromOtherApplications, !cgEvent.isLinearMouseSyntheticEvent {\n            os_log(\n                \"Return noop transformer because this event is sent by %{public}s\",\n                log: Self.log,\n                type: .info,\n                sourcePid?.bundleIdentifier ?? \"(unknown)\"\n            )\n            return []\n        }\n        if let sourceBundleIdentifier = sourcePid?.bundleIdentifier,\n           sourceBundleIdentifierBypassSet.contains(sourceBundleIdentifier) {\n            os_log(\n                \"Return noop transformer because the source application %{public}s is in the bypass set\",\n                log: Self.log,\n                type: .info,\n                sourceBundleIdentifier\n            )\n            return []\n        }\n\n        let pid = mouseLocationPid ?? targetPid\n        let device = DeviceManager.shared.deviceFromCGEvent(cgEvent)\n\n        return get(withDevice: device, withPid: pid, withDisplay: display, updateActiveCacheKey: true)\n    }\n\n    func get(withDevice device: Device?, withPid pid: pid_t?, withDisplay display: String?) -> EventTransformer {\n        if EventThread.shared.isCurrent {\n            return getOnCurrentThread(withDevice: device, withPid: pid, withDisplay: display)\n        }\n\n        if let transformer = EventThread.shared.performAndWait({\n            self.getOnCurrentThread(withDevice: device, withPid: pid, withDisplay: display)\n        }) {\n            return transformer\n        }\n\n        return getOnCurrentThread(withDevice: device, withPid: pid, withDisplay: display)\n    }\n\n    private func getOnCurrentThread(\n        withDevice device: Device?,\n        withPid pid: pid_t?,\n        withDisplay display: String?\n    ) -> EventTransformer {\n        get(withDevice: device, withPid: pid, withDisplay: display, updateActiveCacheKey: false)\n    }\n\n    func handleLogitechControlEvent(_ context: LogitechEventContext) -> Bool {\n        if EventThread.shared.isCurrent {\n            return handleLogitechControlEventOnCurrentThread(context)\n        }\n\n        if let handled = EventThread.shared.performAndWait({\n            self.handleLogitechControlEventOnCurrentThread(context)\n        }) {\n            return handled\n        }\n\n        return handleLogitechControlEventOnCurrentThread(context)\n    }\n\n    private func handleLogitechControlEventOnCurrentThread(_ context: LogitechEventContext) -> Bool {\n        let transformer = get(withDevice: context.device, withPid: context.pid, withDisplay: context.display)\n        return (transformer as? LogitechControlEventHandling)?.handleLogitechControlEvent(context) ?? false\n    }\n\n    private func get(\n        withDevice device: Device?,\n        withPid pid: pid_t?,\n        withDisplay display: String?,\n        updateActiveCacheKey: Bool\n    ) -> EventTransformer {\n        let prevActiveCacheKey = activeCacheKey\n        if updateActiveCacheKey {\n            activeCacheKey = nil\n        }\n        defer {\n            if updateActiveCacheKey,\n               let prevActiveCacheKey,\n               prevActiveCacheKey != activeCacheKey {\n                transition(\n                    from: eventTransformerCache.value(forKey: prevActiveCacheKey),\n                    to: activeCacheKey.flatMap { eventTransformerCache.value(forKey: $0) }\n                )\n            }\n        }\n\n        let cacheKey = CacheKey(\n            deviceMatcher: device.map { DeviceMatcher(of: $0) },\n            pid: pid,\n            screen: display\n        )\n        if updateActiveCacheKey {\n            activeCacheKey = cacheKey\n        }\n        if let eventTransformer = eventTransformerCache.value(forKey: cacheKey) {\n            return eventTransformer\n        }\n\n        let scheme = ConfigurationState.shared.configuration.matchScheme(\n            withDevice: device,\n            withPid: pid,\n            withDisplay: display\n        )\n\n        // TODO: Patch EventTransformer instead of rebuilding it\n\n        os_log(\n            \"Initialize EventTransformer with scheme: %{public}@ (device=%{public}@, pid=%{public}@, screen=%{public}@)\",\n            log: Self.log,\n            type: .info,\n            String(describing: scheme),\n            String(describing: device),\n            String(describing: pid),\n            String(describing: display)\n        )\n\n        var eventTransformer: [EventTransformer] = []\n\n        if let reverse = scheme.scrolling.$reverse {\n            let vertical = reverse.vertical ?? false\n            let horizontal = reverse.horizontal ?? false\n\n            if vertical || horizontal {\n                eventTransformer.append(ReverseScrollingTransformer(vertically: vertical, horizontally: horizontal))\n            }\n        }\n\n        let smoothed = Scheme.Scrolling.Bidirectional(\n            vertical: scheme.scrolling.smoothed.vertical?.isEnabled == true ? scheme.scrolling.smoothed.vertical : nil,\n            horizontal: scheme.scrolling.smoothed.horizontal?.isEnabled == true ? scheme.scrolling.smoothed\n                .horizontal : nil\n        )\n        let hasSmoothedScrolling = smoothed.vertical != nil || smoothed.horizontal != nil\n\n        if let modifiers = scheme.scrolling.$modifiers,\n           hasSmoothedScrolling {\n            eventTransformer.append(ModifierActionsTransformer(modifiers: modifiers))\n        }\n\n        if hasSmoothedScrolling {\n            eventTransformer.append(SmoothedScrollingTransformer(smoothed: smoothed))\n        }\n\n        if let distance = scheme.scrolling.distance.horizontal {\n            if smoothed.horizontal == nil {\n                eventTransformer.append(LinearScrollingHorizontalTransformer(distance: distance))\n            }\n        }\n\n        if let distance = scheme.scrolling.distance.vertical {\n            if smoothed.vertical == nil {\n                eventTransformer.append(LinearScrollingVerticalTransformer(distance: distance))\n            }\n        }\n\n        let acceleration = Scheme.Scrolling.Bidirectional<Decimal>(\n            vertical: smoothed.vertical == nil ? scheme.scrolling.acceleration.vertical : nil,\n            horizontal: smoothed.horizontal == nil ? scheme.scrolling.acceleration.horizontal : nil\n        )\n        let speed = Scheme.Scrolling.Bidirectional<Decimal>(\n            vertical: smoothed.vertical == nil ? scheme.scrolling.speed.vertical : nil,\n            horizontal: smoothed.horizontal == nil ? scheme.scrolling.speed.horizontal : nil\n        )\n\n        if acceleration.vertical ?? 1 != 1 || acceleration.horizontal ?? 1 != 1 ||\n            speed.vertical ?? 0 != 0 || speed.horizontal ?? 0 != 0 {\n            eventTransformer\n                .append(ScrollingAccelerationSpeedAdjustmentTransformer(\n                    acceleration: acceleration,\n                    speed: speed\n                ))\n        }\n\n        if let timeout = scheme.buttons.clickDebouncing.timeout, timeout > 0,\n           let buttons = scheme.buttons.clickDebouncing.buttons {\n            let resetTimerOnMouseUp = scheme.buttons.clickDebouncing.resetTimerOnMouseUp ?? false\n            for button in buttons {\n                eventTransformer.append(ClickDebouncingTransformer(\n                    for: button,\n                    timeout: TimeInterval(timeout) / 1000,\n                    resetTimerOnMouseUp: resetTimerOnMouseUp\n                ))\n            }\n        }\n\n        if let modifiers = scheme.scrolling.$modifiers,\n           !hasSmoothedScrolling {\n            eventTransformer.append(ModifierActionsTransformer(modifiers: modifiers))\n        }\n\n        if scheme.buttons.switchPrimaryButtonAndSecondaryButtons == true {\n            eventTransformer.append(SwitchPrimaryAndSecondaryButtonsTransformer())\n        }\n\n        if let autoScrollTransformer = autoScrollTransformer(for: scheme.buttons.$autoScroll) {\n            eventTransformer.append(autoScrollTransformer)\n        }\n\n        if let gesture = scheme.buttons.$gesture,\n           gesture.enabled ?? false,\n           let trigger = gesture.trigger,\n           trigger.button != nil {\n            eventTransformer.append(GestureButtonTransformer(\n                trigger: trigger,\n                threshold: Double(gesture.threshold ?? 50),\n                deadZone: Double(gesture.deadZone ?? 40),\n                cooldownMs: gesture.cooldownMs ?? 500,\n                actions: gesture.actions\n            ))\n        }\n\n        if let mappings = scheme.buttons.mappings {\n            eventTransformer.append(ButtonActionsTransformer(\n                mappings: mappings,\n                universalBackForward: scheme.buttons.universalBackForward\n            ))\n        }\n\n        if let universalBackForward = scheme.buttons.universalBackForward,\n           universalBackForward != .none {\n            eventTransformer.append(UniversalBackForwardTransformer(universalBackForward: universalBackForward))\n        }\n\n        if let redirectsToScroll = scheme.pointer.redirectsToScroll, redirectsToScroll {\n            eventTransformer.append(PointerRedirectsToScrollTransformer())\n        }\n\n        eventTransformerCache.setValue(eventTransformer, forKey: cacheKey)\n\n        return eventTransformer\n    }\n\n    private func autoScrollTransformer(for autoScroll: Scheme.Buttons.AutoScroll?) -> AutoScrollTransformer? {\n        if let sharedAutoScrollTransformer, sharedAutoScrollTransformer.isAutoscrollActive {\n            return sharedAutoScrollTransformer\n        }\n\n        guard let autoScroll,\n              autoScroll.enabled ?? false,\n              let trigger = autoScroll.trigger,\n              trigger.valid else {\n            sharedAutoScrollTransformer?.deactivate()\n            sharedAutoScrollTransformer = nil\n            return nil\n        }\n\n        let modes = autoScroll.normalizedModes\n        let speed = autoScroll.speed?.asTruncatedDouble ?? 1\n        let preserveNativeMiddleClick = autoScroll.preserveNativeMiddleClick ?? true\n\n        if let sharedAutoScrollTransformer,\n           sharedAutoScrollTransformer.matchesConfiguration(\n               trigger: trigger,\n               modes: modes,\n               speed: speed,\n               preserveNativeMiddleClick: preserveNativeMiddleClick\n           ) {\n            return sharedAutoScrollTransformer\n        }\n\n        sharedAutoScrollTransformer?.deactivate()\n        sharedAutoScrollTransformer = nil\n        let transformer = AutoScrollTransformer(\n            trigger: trigger,\n            modes: modes,\n            speed: speed,\n            preserveNativeMiddleClick: preserveNativeMiddleClick\n        )\n        sharedAutoScrollTransformer = transformer\n        return transformer\n    }\n\n    private func transition(from previous: EventTransformer?, to current: EventTransformer?) {\n        let preservedAutoScrollTransformer = sharedAutoScrollTransformer?.isAutoscrollActive == true\n            ? sharedAutoScrollTransformer\n            : nil\n\n        deactivate(previous, excluding: preservedAutoScrollTransformer)\n        reactivate(current, excluding: preservedAutoScrollTransformer)\n    }\n\n    private func resetState() {\n        let oldAutoScroll = sharedAutoScrollTransformer\n        sharedAutoScrollTransformer = nil\n        activeCacheKey = nil\n        eventTransformerCache.removeAllValues()\n        oldAutoScroll?.deactivate()\n    }\n\n    private func deactivate(\n        _ transformer: EventTransformer?,\n        excluding preservedAutoScrollTransformer: AutoScrollTransformer?\n    ) {\n        guard let transformer else {\n            return\n        }\n\n        if let transformers = transformer as? [EventTransformer] {\n            for transformer in transformers {\n                if let preservedAutoScrollTransformer,\n                   let autoScrollTransformer = transformer as? AutoScrollTransformer,\n                   autoScrollTransformer === preservedAutoScrollTransformer {\n                    continue\n                }\n\n                (transformer as? Deactivatable)?.deactivate()\n            }\n            return\n        }\n\n        if let preservedAutoScrollTransformer,\n           let autoScrollTransformer = transformer as? AutoScrollTransformer,\n           autoScrollTransformer === preservedAutoScrollTransformer {\n            return\n        }\n\n        (transformer as? Deactivatable)?.deactivate()\n    }\n\n    private func reactivate(\n        _ transformer: EventTransformer?,\n        excluding preservedAutoScrollTransformer: AutoScrollTransformer?\n    ) {\n        guard let transformer else {\n            return\n        }\n\n        if let transformers = transformer as? [EventTransformer] {\n            for transformer in transformers {\n                if let preservedAutoScrollTransformer,\n                   let autoScrollTransformer = transformer as? AutoScrollTransformer,\n                   autoScrollTransformer === preservedAutoScrollTransformer {\n                    continue\n                }\n\n                (transformer as? Deactivatable)?.reactivate()\n            }\n            return\n        }\n\n        if let preservedAutoScrollTransformer,\n           let autoScrollTransformer = transformer as? AutoScrollTransformer,\n           autoScrollTransformer === preservedAutoScrollTransformer {\n            return\n        }\n\n        (transformer as? Deactivatable)?.reactivate()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/GestureButtonTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport DockKit\nimport Foundation\nimport KeyKit\nimport os.log\n\nclass GestureButtonTransformer {\n    static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"GestureButton\")\n\n    // Configuration\n    private let trigger: Scheme.Buttons.Mapping\n    private let triggerMouseButton: CGMouseButton\n    private let threshold: Double\n    private let deadZone: Double\n    private let cooldownMs: Int\n    private let actions: Scheme.Buttons.Gesture.Actions\n\n    /// State machine\n    private enum State {\n        case idle\n        case tracking(startTime: UInt64, deltaX: Double, deltaY: Double)\n        case triggered\n        case cooldown(until: UInt64, released: Bool)\n    }\n\n    private var state: State = .idle\n\n    init(\n        trigger: Scheme.Buttons.Mapping,\n        threshold: Double,\n        deadZone: Double,\n        cooldownMs: Int,\n        actions: Scheme.Buttons.Gesture.Actions\n    ) {\n        self.trigger = trigger\n        let defaultButton = UInt32(CGMouseButton.center.rawValue)\n        let buttonNumber = trigger.button?.syntheticMouseButtonNumber ?? Int(defaultButton)\n        triggerMouseButton = CGMouseButton(rawValue: UInt32(buttonNumber)) ?? .center\n        self.threshold = threshold\n        self.deadZone = deadZone\n        self.cooldownMs = cooldownMs\n        self.actions = actions\n    }\n}\n\nextension GestureButtonTransformer: EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent? {\n        // Check if we're in cooldown\n        if case let .cooldown(until, released) = state {\n            if DispatchTime.now().uptimeNanoseconds < until {\n                // Still in cooldown - consume our button events\n                if matchesTriggerButton(event) {\n                    if event.type == mouseUpEventType, !released {\n                        os_log(\"Releasing trigger button during cooldown\", log: Self.log, type: .debug)\n                        state = .cooldown(until: until, released: true)\n                        event.isGestureCleanupRelease = true\n                        return event\n                    }\n                    os_log(\"Event consumed during cooldown\", log: Self.log, type: .debug)\n                    return nil\n                }\n                return event\n            }\n            // Cooldown expired, return to idle\n            state = .idle\n        }\n\n        // Route based on event type\n        switch event.type {\n        case mouseDownEventType:\n            return handleButtonDown(event)\n        case mouseDraggedEventType, .mouseMoved:\n            return handleDragged(event)\n        case mouseUpEventType:\n            return handleButtonUp(event)\n        default:\n            return event\n        }\n    }\n\n    private var mouseDownEventType: CGEventType {\n        triggerMouseButton.fixedCGEventType(of: .otherMouseDown)\n    }\n\n    private var mouseUpEventType: CGEventType {\n        triggerMouseButton.fixedCGEventType(of: .otherMouseUp)\n    }\n\n    private var mouseDraggedEventType: CGEventType {\n        triggerMouseButton.fixedCGEventType(of: .otherMouseDragged)\n    }\n\n    private func matchesTriggerButton(_ event: CGEvent) -> Bool {\n        guard let eventButton = MouseEventView(event).mouseButton else {\n            return false\n        }\n        return eventButton == triggerMouseButton\n    }\n\n    private func matchesActivationTrigger(_ event: CGEvent) -> Bool {\n        guard matchesTriggerButton(event) else {\n            return false\n        }\n        return trigger.matches(modifierFlags: event.flags)\n    }\n\n    private func handleButtonDown(_ event: CGEvent) -> CGEvent? {\n        guard matchesActivationTrigger(event) else {\n            return event\n        }\n\n        // Start tracking\n        state = .tracking(startTime: DispatchTime.now().uptimeNanoseconds, deltaX: 0, deltaY: 0)\n//        os_log(\"Started tracking gesture\", log: Self.log, type: .info)\n\n        // Pass through the button down event\n        return event\n    }\n\n    private func handleDragged(_ event: CGEvent) -> CGEvent? {\n        guard case .tracking(let startTime, var deltaX, var deltaY) = state else {\n            return event\n        }\n\n        let isMouseMoved = event.type == .mouseMoved\n\n        // For drag events, verify button match.\n        // mouseMoved events don't carry a button number but are used to track\n        // movement when the trigger is a Logitech HID++ control (which generates\n        // synthetic button events that don't produce OS-level drag events).\n        if !isMouseMoved {\n            guard matchesTriggerButton(event) else {\n                return event\n            }\n        }\n\n        // Accumulate deltas\n        let eventDeltaX = event.getDoubleValueField(.mouseEventDeltaX)\n        let eventDeltaY = event.getDoubleValueField(.mouseEventDeltaY)\n        deltaX += eventDeltaX\n        deltaY += eventDeltaY\n\n//        os_log(\"Accumulated delta: (%.2f, %.2f)\", log: Self.log, type: .debug, deltaX, deltaY)\n\n        // Check for timeout (3 seconds)\n        let elapsed = DispatchTime.now().uptimeNanoseconds - startTime\n        if elapsed > 3_000_000_000 {\n//            os_log(\"Gesture timeout, resetting\", log: Self.log, type: .info)\n            state = .idle\n            return event\n        }\n\n        // Check if threshold is met\n        if let action = detectGesture(deltaX: deltaX, deltaY: deltaY) {\n            os_log(\"Gesture detected: %{public}@\", log: Self.log, type: .info, String(describing: action))\n\n            // Execute the gesture\n            do {\n                try executeGesture(action)\n                state = .triggered\n\n                // Enter cooldown\n                let cooldownNanos = UInt64(cooldownMs) * 1_000_000\n                state = .cooldown(until: DispatchTime.now().uptimeNanoseconds + cooldownNanos, released: false)\n\n                os_log(\"Entering cooldown for %d ms\", log: Self.log, type: .info, cooldownMs)\n            } catch {\n                os_log(\"Failed to execute gesture: %{public}@\", log: Self.log, type: .error, error.localizedDescription)\n                state = .idle\n            }\n\n            // Consume the event\n            return nil\n        }\n\n        // Update state with new deltas\n        state = .tracking(startTime: startTime, deltaX: deltaX, deltaY: deltaY)\n\n        // Consume drag events while tracking; pass through mouseMoved events\n        return isMouseMoved ? event : nil\n    }\n\n    private func handleButtonUp(_ event: CGEvent) -> CGEvent? {\n        guard matchesTriggerButton(event) else {\n            return event\n        }\n\n        // If we were tracking but didn't trigger, reset to idle\n        if case .tracking = state {\n//            os_log(\"Button released before threshold, resetting\", log: Self.log, type: .info)\n            state = .idle\n            // Pass through the button up event so it can be used as a normal click\n            return event\n        }\n\n        // If we triggered, enter cooldown and pass the release through\n        if case .triggered = state {\n            let cooldownNanos = UInt64(cooldownMs) * 1_000_000\n            state = .cooldown(until: DispatchTime.now().uptimeNanoseconds + cooldownNanos, released: true)\n            event.isGestureCleanupRelease = true\n            return event\n        }\n\n        return event\n    }\n\n    private func detectGesture(deltaX: Double, deltaY: Double) -> Scheme.Buttons.Gesture.GestureAction? {\n        let absDeltaX = abs(deltaX)\n        let absDeltaY = abs(deltaY)\n\n        // Calculate magnitude\n        let magnitude = sqrt(deltaX * deltaX + deltaY * deltaY)\n        guard magnitude >= threshold else {\n            return nil\n        }\n\n//        os_log(\n//            \"Gesture check: deltaX=%.1f, deltaY=%.1f, magnitude=%.1f, deadZone=%.1f\",\n//            log: Self.log,\n//            type: .info,\n//            deltaX,\n//            deltaY,\n//            magnitude,\n//            deadZone\n//        )\n\n        // Determine dominant axis\n        if absDeltaX > absDeltaY {\n            // Horizontal gesture\n            guard absDeltaY < deadZone else {\n//                os_log(\n//                    \"Horizontal gesture rejected: absDeltaY=%.1f >= deadZone=%.1f\",\n//                    log: Self.log,\n//                    type: .info,\n//                    absDeltaY,\n//                    deadZone\n//                )\n                return nil\n            }\n            // Use defaults if actions not configured\n            return deltaX > 0 ? (actions.right ?? .spaceRight) : (actions.left ?? .spaceLeft)\n        }\n        // Vertical gesture\n        guard absDeltaX < deadZone else {\n//                os_log(\n//                    \"Vertical gesture rejected: absDeltaX=%.1f >= deadZone=%.1f\",\n//                    log: Self.log,\n//                    type: .info,\n//                    absDeltaX,\n//                    deadZone\n//                )\n            return nil\n        }\n        // Use defaults if actions not configured\n        return deltaY > 0 ? (actions.down ?? .appExpose) : (actions.up ?? .missionControl)\n    }\n\n    private func executeGesture(_ action: Scheme.Buttons.Gesture.GestureAction) throws {\n        switch action {\n        case .none:\n            break\n\n        case .spaceLeft:\n            try postSymbolicHotKey(.spaceLeft)\n\n        case .spaceRight:\n            try postSymbolicHotKey(.spaceRight)\n\n        case .missionControl:\n            missionControl()\n\n        case .appExpose:\n            appExpose()\n\n        case .showDesktop:\n            showDesktop()\n\n        case .launchpad:\n            launchpad()\n        }\n    }\n}\n\nextension GestureButtonTransformer: LogitechControlEventHandling {\n    func handleLogitechControlEvent(_ context: LogitechEventContext) -> Bool {\n        guard let triggerLogitechControl = trigger.button?.logitechControl,\n              context.controlIdentity.matches(triggerLogitechControl) else {\n            return false\n        }\n\n        if case let .cooldown(until, _) = state {\n            if DispatchTime.now().uptimeNanoseconds < until {\n                return true\n            }\n            state = .idle\n        }\n\n        if context.isPressed {\n            guard trigger.matches(modifierFlags: context.modifierFlags) else {\n                return true\n            }\n            state = .tracking(startTime: DispatchTime.now().uptimeNanoseconds, deltaX: 0, deltaY: 0)\n            os_log(\"Started tracking gesture (Logitech control)\", log: Self.log, type: .info)\n        } else {\n            switch state {\n            case .tracking:\n                state = .idle\n            case .cooldown:\n                break\n            default:\n                break\n            }\n        }\n\n        return true\n    }\n}\n\nextension GestureButtonTransformer: Deactivatable {\n    func deactivate() {\n        state = .idle\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/LinearScrollingHorizontalTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nclass LinearScrollingHorizontalTransformer: EventTransformer {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"LinearScrollingHorizontal\")\n\n    private let distance: Scheme.Scrolling.Distance\n\n    init(distance: Scheme.Scrolling.Distance) {\n        self.distance = distance\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .scrollWheel else {\n            return event\n        }\n\n        if event.isLinearMouseSyntheticEvent {\n            return event\n        }\n\n        if case .auto = distance {\n            return event\n        }\n\n        let view = ScrollWheelEventView(event)\n\n        guard view.deltaXSignum != 0 else {\n            return event\n        }\n\n        guard view.momentumPhase == .none else {\n            return nil\n        }\n\n        let (continuous, oldValue) = (view.continuous, view.matrixValue)\n        let deltaXSignum = view.deltaXSignum\n\n        switch distance {\n        case .auto:\n            return event\n\n        case let .line(value):\n            view.continuous = false\n            view.deltaX = deltaXSignum * Int64(value)\n            view.deltaY = 0\n\n        case let .pixel(value):\n            view.continuous = true\n            view.deltaXPt = Double(deltaXSignum) * value.asTruncatedDouble\n            view.deltaXFixedPt = Double(deltaXSignum) * value.asTruncatedDouble\n            view.deltaYPt = 0\n            view.deltaYFixedPt = 0\n        }\n\n        os_log(\n            \"continuous=%{public}@, oldValue=%{public}@, newValue=%{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: continuous),\n            String(describing: oldValue),\n            String(describing: view.matrixValue)\n        )\n\n        return event\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/LinearScrollingVerticalTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nclass LinearScrollingVerticalTransformer: EventTransformer {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"LinearScrollingVertical\")\n\n    private let distance: Scheme.Scrolling.Distance\n\n    init(distance: Scheme.Scrolling.Distance) {\n        self.distance = distance\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .scrollWheel else {\n            return event\n        }\n\n        if event.isLinearMouseSyntheticEvent {\n            return event\n        }\n\n        if case .auto = distance {\n            return event\n        }\n\n        let view = ScrollWheelEventView(event)\n\n        guard view.deltaYSignum != 0 else {\n            return event\n        }\n\n        guard view.momentumPhase == .none else {\n            return nil\n        }\n\n        let (continuous, oldValue) = (view.continuous, view.matrixValue)\n        let deltaYSignum = view.deltaYSignum\n\n        switch distance {\n        case .auto:\n            return event\n\n        case let .line(value):\n            view.continuous = false\n            view.deltaY = deltaYSignum * Int64(value)\n            view.deltaX = 0\n\n        case let .pixel(value):\n            view.continuous = true\n            view.deltaYPt = Double(deltaYSignum) * value.asTruncatedDouble\n            view.deltaYFixedPt = Double(deltaYSignum) * value.asTruncatedDouble\n            view.deltaXPt = 0\n            view.deltaXFixedPt = 0\n        }\n\n        os_log(\n            \"continuous=%{public}@, oldValue=%{public}@, newValue=%{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: continuous),\n            String(describing: oldValue),\n            String(describing: view.matrixValue)\n        )\n\n        return event\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/LogitechEventContext.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nstruct LogitechEventContext {\n    let device: Device?\n    let pid: pid_t?\n    let display: String?\n    let mouseLocation: CGPoint\n    let controlIdentity: LogitechControlIdentity\n    let isPressed: Bool\n    let modifierFlags: CGEventFlags\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/ModifierActionsTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport GestureKit\nimport KeyKit\nimport os.log\n\nclass ModifierActionsTransformer {\n    private static let log = OSLog(\n        subsystem: Bundle.main.bundleIdentifier!,\n        category: \"ModifierActionsTransformer\"\n    )\n\n    private static let keySimulator = KeySimulator()\n\n    typealias Modifiers = Scheme.Scrolling.Bidirectional<Scheme.Scrolling.Modifiers>\n    typealias Action = Scheme.Scrolling.Modifiers.Action\n\n    private let modifiers: Modifiers\n\n    private var pinchZoomBegan = false\n\n    init(modifiers: Modifiers) {\n        self.modifiers = modifiers\n    }\n}\n\nextension ModifierActionsTransformer: EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent? {\n        if pinchZoomBegan {\n            return handlePinchZoom(event)\n        }\n\n        guard event.type == .scrollWheel else {\n            return event\n        }\n\n        let scrollWheelEventView = ScrollWheelEventView(event)\n        guard let modifiers = scrollWheelEventView.deltaYSignum != 0\n            ? modifiers.vertical\n            : modifiers.horizontal else {\n            return event\n        }\n\n        let actions: [(CGEventFlags.Element, Action?)] = [\n            (.maskCommand, modifiers.command),\n            (.maskShift, modifiers.shift),\n            (.maskAlternate, modifiers.option),\n            (.maskControl, modifiers.control)\n        ]\n        var event = event\n        for case let (flag, action) in actions where event.flags.contains(flag) {\n            if let action, action != .auto {\n                guard let handledEvent = handleModifierKeyAction(for: event, action: action) else {\n                    return nil\n                }\n                event = handledEvent\n                event.flags.remove(flag)\n            }\n        }\n        return event\n    }\n\n    private func handleModifierKeyAction(for event: CGEvent, action: Action) -> CGEvent? {\n        let scrollWheelEventView = ScrollWheelEventView(event)\n\n        switch action {\n        case .auto, .ignore:\n            break\n        case .preventDefault:\n            return nil\n        case .alterOrientation:\n            scrollWheelEventView.swapXY()\n        case let .changeSpeed(scale: scale):\n            scrollWheelEventView.scale(factor: scale.asTruncatedDouble)\n        case .zoom:\n            let scrollWheelEventView = ScrollWheelEventView(event)\n            let deltaSignum = scrollWheelEventView.deltaYSignum != 0 ? scrollWheelEventView\n                .deltaYSignum : scrollWheelEventView.deltaXSignum\n            if deltaSignum == 0 {\n                return event\n            }\n            if deltaSignum > 0 {\n                try? Self.keySimulator.press(.command, .numpadPlus, tap: .cgSessionEventTap)\n            } else {\n                try? Self.keySimulator.press(.command, .numpadMinus, tap: .cgSessionEventTap)\n            }\n            return nil\n        case .pinchZoom:\n            return handlePinchZoom(event)\n        }\n\n        return event\n    }\n\n    private func handlePinchZoom(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .scrollWheel || event.type == .flagsChanged else {\n            return event\n        }\n\n        if event.type == .flagsChanged {\n            pinchZoomBegan = false\n            GestureEvent(zoomSource: nil, phase: .ended, magnification: 0)?.post(tap: .cgSessionEventTap)\n            os_log(\"pinch zoom ended\", log: Self.log, type: .info)\n            return event\n        }\n\n        if !pinchZoomBegan {\n            GestureEvent(zoomSource: nil, phase: .began, magnification: 0)?.post(tap: .cgSessionEventTap)\n            pinchZoomBegan = true\n            os_log(\"pinch zoom began\", log: Self.log, type: .info)\n        }\n\n        let scrollWheelEventView = ScrollWheelEventView(event)\n        let magnification = Double(scrollWheelEventView.deltaYPt) * 0.005\n        GestureEvent(zoomSource: nil, phase: .changed, magnification: magnification)?.post(tap: .cgSessionEventTap)\n        os_log(\"pinch zoom changed: magnification=%f\", log: Self.log, type: .info, magnification)\n\n        return nil\n    }\n}\n\nextension ModifierActionsTransformer: Deactivatable {\n    func deactivate() {\n        if pinchZoomBegan {\n            pinchZoomBegan = false\n            GestureEvent(zoomSource: nil, phase: .ended, magnification: 0)?.post(tap: .cgSessionEventTap)\n            os_log(\"ModifierActionsTransformer is inactive, pinch zoom ended\", log: Self.log, type: .info)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/PointerRedirectsToScrollTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport Foundation\n\nclass PointerRedirectsToScrollTransformer: EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .mouseMoved else {\n            return event\n        }\n\n        // Despite making this function return nil, the mouseMoved event\n        // still causes the cursor to move, so we need to manually move\n        // the cursor to maintain a fixed position during scrolling.\n        CGWarpMouseCursorPosition(event.location)\n\n        let deltaX = event.getDoubleValueField(.mouseEventDeltaX)\n        let deltaY = event.getDoubleValueField(.mouseEventDeltaY)\n        let scrollX = -deltaX\n        let scrollY = -deltaY\n\n        if let scrollEvent = CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .pixel,\n            wheelCount: 2,\n            wheel1: Int32(scrollY),\n            wheel2: Int32(scrollX),\n            wheel3: 0\n        ) {\n            scrollEvent.post(tap: .cghidEventTap)\n        }\n\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/ReverseScrollingTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nclass ReverseScrollingTransformer: EventTransformer {\n    private let vertically: Bool\n    private let horizontally: Bool\n\n    init(vertically: Bool = false, horizontally: Bool = false) {\n        self.vertically = vertically\n        self.horizontally = horizontally\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .scrollWheel else {\n            return event\n        }\n\n        if event.isLinearMouseSyntheticEvent {\n            return event\n        }\n\n        let view = ScrollWheelEventView(event)\n        view.negate(vertically: vertically, horizontally: horizontally)\n        return event\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/ScrollingAccelerationSpeedAdjustmentTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nclass ScrollingAccelerationSpeedAdjustmentTransformer: EventTransformer {\n    private static let log = OSLog(\n        subsystem: Bundle.main.bundleIdentifier!,\n        category: \"ScrollingAccelerationSpeedAdjustment\"\n    )\n\n    private let acceleration: Scheme.Scrolling.Bidirectional<Decimal>\n    private let speed: Scheme.Scrolling.Bidirectional<Decimal>\n\n    init(\n        acceleration: Scheme.Scrolling.Bidirectional<Decimal>,\n        speed: Scheme.Scrolling.Bidirectional<Decimal>\n    ) {\n        self.acceleration = acceleration\n        self.speed = speed\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .scrollWheel else {\n            return event\n        }\n\n        if event.isLinearMouseSyntheticEvent {\n            return event\n        }\n\n        let scrollWheelEventView = ScrollWheelEventView(event)\n        let deltaYSignum = scrollWheelEventView.deltaYSignum\n        let deltaXSignum = scrollWheelEventView.deltaXSignum\n\n        if deltaYSignum != 0,\n           let acceleration = acceleration.vertical?.asTruncatedDouble, acceleration != 1 {\n            scrollWheelEventView.scale(factorY: acceleration)\n            os_log(\"deltaY: acceleration=%{public}f\", log: Self.log, type: .info, acceleration)\n        }\n\n        if deltaXSignum != 0,\n           let acceleration = acceleration.horizontal?.asTruncatedDouble, acceleration != 1 {\n            scrollWheelEventView.scale(factorX: acceleration)\n            os_log(\"deltaX: acceleration=%{public}f\", log: Self.log, type: .info, acceleration)\n        }\n\n        if deltaYSignum != 0,\n           let speed = speed.vertical?.asTruncatedDouble, speed != 0 {\n            let targetPt = scrollWheelEventView.deltaYPt + Double(deltaYSignum) * speed\n            scrollWheelEventView.deltaY = deltaYSignum * max(1, Int64(abs(targetPt) / 10))\n            scrollWheelEventView.deltaYPt = targetPt\n            scrollWheelEventView.deltaYFixedPt = targetPt / 10\n            // TODO: Test if ioHidScrollY needs to be modified.\n            os_log(\"deltaY: speed=%{public}f\", log: Self.log, type: .info, speed)\n        }\n\n        if deltaXSignum != 0,\n           let speed = speed.horizontal?.asTruncatedDouble, speed != 0 {\n            let targetPt = scrollWheelEventView.deltaXPt + Double(deltaXSignum) * speed\n            scrollWheelEventView.deltaX = deltaXSignum * max(1, Int64(abs(targetPt) / 10))\n            scrollWheelEventView.deltaXPt = targetPt\n            scrollWheelEventView.deltaXFixedPt = targetPt / 10\n            os_log(\"deltaX: speed=%{public}f\", log: Self.log, type: .info, speed)\n        }\n\n        os_log(\"newValue=%{public}@\", log: Self.log, type: .info, String(describing: scrollWheelEventView.matrixValue))\n\n        return event\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/SmoothedScrollingEngine.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport Foundation\n\nfinal class SmoothedScrollingEngine {\n    enum Phase {\n        case touchBegan\n        case touchChanged\n        case touchEnded\n        case momentumBegan\n        case momentumChanged\n        case momentumEnded\n    }\n\n    enum Axis {\n        case horizontal\n        case vertical\n    }\n\n    struct Emission {\n        var deltaX: Double\n        var deltaY: Double\n        var phase: Phase\n    }\n\n    private enum SessionState {\n        case idle\n        case touching\n        case momentum\n    }\n\n    private enum AxisBehavior {\n        case passthrough\n        case smoothed(AxisTuning)\n    }\n\n    private struct AxisTuning {\n        private static let legacyUpperBound = 3.0\n\n        let configuration: Scheme.Scrolling.Smoothed\n\n        init(configuration: Scheme.Scrolling.Smoothed) {\n            self.configuration = configuration\n        }\n\n        private var presetProfile: Scheme.Scrolling.Smoothed.PresetProfile {\n            configuration.resolvedPresetProfile\n        }\n\n        private var response: Double {\n            (configuration.response?.asTruncatedDouble ?? 0.45)\n                .clamped(to: Scheme.Scrolling.Smoothed.responseRange)\n        }\n\n        private var speed: Double {\n            (configuration.speed?.asTruncatedDouble ?? 1)\n                .clamped(to: Scheme.Scrolling.Smoothed.speedRange)\n        }\n\n        private var acceleration: Double {\n            (configuration.acceleration?.asTruncatedDouble ?? 1.2)\n                .clamped(to: Scheme.Scrolling.Smoothed.accelerationRange)\n        }\n\n        private var inertia: Double {\n            (configuration.inertia?.asTruncatedDouble ?? 0.65)\n                .clamped(to: Scheme.Scrolling.Smoothed.inertiaRange)\n        }\n\n        func desiredVelocity(for input: Double) -> Double {\n            guard input != 0 else {\n                return 0\n            }\n\n            let profile = presetProfile\n            let baseMagnitude = abs(input)\n            let normalizedMagnitude = (baseMagnitude / (baseMagnitude + 24)).clamped(to: 0 ... 1)\n            let curvedMagnitude = pow(normalizedMagnitude, profile.inputExponent)\n            let magnitude = baseMagnitude * curvedMagnitude\n            let speedBoost = 0.85 + speed * 0.4\n            let accelerationBoost = 1 + acceleration * profile.accelerationGain\n            let velocity = magnitude * profile.velocityScale * speedBoost * accelerationBoost\n\n            return input.sign == .minus ? -velocity : velocity\n        }\n\n        private func reengagementDominance(inputVelocity: Double, currentVelocity: Double) -> Double {\n            let inputMagnitude = abs(inputVelocity)\n            let currentMagnitude = abs(currentVelocity)\n\n            guard inputMagnitude > 0, currentMagnitude > 0 else {\n                return 0\n            }\n\n            return (currentMagnitude / inputMagnitude).clamped(to: 0 ... 1)\n        }\n\n        private func tailRecovery(inputVelocity: Double, currentVelocity: Double) -> Double {\n            let dominance = reengagementDominance(inputVelocity: inputVelocity, currentVelocity: currentVelocity)\n            return ((0.75 - dominance) / 0.75).clamped(to: 0 ... 1)\n        }\n\n        func reengagedDesiredVelocity(for input: Double, currentVelocity: Double) -> Double {\n            let inputVelocity = desiredVelocity(for: input)\n\n            guard currentVelocity != 0 else {\n                return inputVelocity\n            }\n\n            let sameDirection = inputVelocity.sign == currentVelocity.sign\n            if sameDirection {\n                let carryFactor = (0.06 + response * 0.06 + acceleration * 0.01).clamped(to: 0.06 ... 0.16)\n                let ceilingFactor = (1.01 + presetProfile.response * 0.08 + response * 0.06).clamped(to: 1.02 ... 1.12)\n                let carriedMagnitude = min(\n                    abs(currentVelocity) + abs(inputVelocity) * carryFactor,\n                    max(abs(currentVelocity), abs(inputVelocity)) * ceilingFactor\n                )\n                let recovery = pow(tailRecovery(inputVelocity: inputVelocity, currentVelocity: currentVelocity), 0.8)\n                let targetMagnitude = carriedMagnitude + (abs(inputVelocity) - carriedMagnitude) * recovery\n                return currentVelocity.sign == .minus ? -targetMagnitude : targetMagnitude\n            }\n\n            let brakingBlend = (0.50 + response * 0.20).clamped(to: 0.50 ... 0.82)\n            return currentVelocity + (inputVelocity - currentVelocity) * brakingBlend\n        }\n\n        func blendFactor(for dt: TimeInterval) -> Double {\n            let scaled = presetProfile.response * 0.75 + response * 0.8\n            return (scaled * dt * 60).clamped(to: 0.0 ... 1.0)\n        }\n\n        func reengagementBlendFactor(for dt: TimeInterval, desiredVelocity: Double, currentVelocity: Double) -> Double {\n            let baseBlend = blendFactor(for: dt)\n            let softenedBlend = (baseBlend * (0.10 + response * 0.08)).clamped(to: 0.0 ... 0.12)\n            let recovery = pow(tailRecovery(inputVelocity: desiredVelocity, currentVelocity: currentVelocity), 0.55)\n            return (softenedBlend + (baseBlend - softenedBlend) * recovery).clamped(to: softenedBlend ... baseBlend)\n        }\n\n        func reengagementKickFactor(desiredVelocity: Double, currentVelocity: Double) -> Double {\n            guard desiredVelocity != 0, currentVelocity != 0, desiredVelocity.sign == currentVelocity.sign else {\n                return 0\n            }\n\n            let recovery = pow(tailRecovery(inputVelocity: desiredVelocity, currentVelocity: currentVelocity), 0.8)\n            let baseKick = (0.04 + response * 0.04).clamped(to: 0.04 ... 0.08)\n            let tailKick = (0.14 + response * 0.05 + acceleration * 0.02).clamped(to: 0.14 ... 0.28)\n            return (baseKick + tailKick * recovery).clamped(to: 0.04 ... 0.24)\n        }\n\n        func momentumDecay(for dt: TimeInterval) -> Double {\n            let profile = presetProfile\n            let legacyInertiaBoost = ((min(inertia, Self.legacyUpperBound) - 0.65) * 0.05)\n                .clamped(to: -0.08 ... 0.10)\n            let extendedInertiaBoost = max(inertia - Self.legacyUpperBound, 0) * 0.01\n            let decayCeiling = inertia > Self.legacyUpperBound ? 0.99 : 0.98\n            let dtScale = max(dt * 60, 0.25)\n            let decay = (profile.decay + legacyInertiaBoost + extendedInertiaBoost)\n                .clamped(to: 0.72 ... decayCeiling)\n            return pow(decay, dtScale)\n        }\n    }\n\n    private let horizontalBehavior: AxisBehavior\n    private let verticalBehavior: AxisBehavior\n\n    private var sessionState: SessionState = .idle\n    private var lastTickTimestamp: TimeInterval?\n    private var lastInputTimestamp: TimeInterval?\n    private var pendingInputX = 0.0\n    private var pendingInputY = 0.0\n    private var desiredVelocityX = 0.0\n    private var desiredVelocityY = 0.0\n    private var velocityX = 0.0\n    private var velocityY = 0.0\n    private var touchHasBegun = false\n    private var pendingMomentumBegin = false\n    private var reengagedFromMomentum = false\n\n    private let inputGrace: TimeInterval = 1.0 / 25.0\n    private let stopThreshold = 0.5\n    private let axisActivityThreshold = 0.01\n\n    init(smoothed: Scheme.Scrolling.Bidirectional<Scheme.Scrolling.Smoothed>) {\n        horizontalBehavior = smoothed.horizontal.map { .smoothed(.init(configuration: $0)) } ?? .passthrough\n        verticalBehavior = smoothed.vertical.map { .smoothed(.init(configuration: $0)) } ?? .passthrough\n    }\n\n    var isRunning: Bool {\n        switch sessionState {\n        case .idle:\n            return pendingInputX != 0 || pendingInputY != 0\n        case .touching, .momentum:\n            return true\n        }\n    }\n\n    var exclusiveActiveAxis: Axis? {\n        let horizontalActive = axisIsActive(\n            pendingInput: pendingInputX,\n            desiredVelocity: desiredVelocityX,\n            velocity: velocityX\n        )\n        let verticalActive = axisIsActive(\n            pendingInput: pendingInputY,\n            desiredVelocity: desiredVelocityY,\n            velocity: velocityY\n        )\n\n        switch (horizontalActive, verticalActive) {\n        case (true, false):\n            return .horizontal\n        case (false, true):\n            return .vertical\n        default:\n            return nil\n        }\n    }\n\n    func resetOtherAxis(ifExclusiveIncomingAxis incomingAxis: Axis) {\n        guard let activeAxis = exclusiveActiveAxis,\n              activeAxis != incomingAxis else {\n            return\n        }\n\n        switch activeAxis {\n        case .horizontal:\n            pendingInputX = 0\n            desiredVelocityX = 0\n            velocityX = 0\n        case .vertical:\n            pendingInputY = 0\n            desiredVelocityY = 0\n            velocityY = 0\n        }\n\n        if abs(velocityX) <= stopThreshold,\n           abs(velocityY) <= stopThreshold,\n           pendingInputX == 0,\n           pendingInputY == 0 {\n            pendingMomentumBegin = false\n            reengagedFromMomentum = false\n            if sessionState == .momentum {\n                sessionState = .idle\n                touchHasBegun = false\n            }\n        }\n    }\n\n    func feed(deltaX: Double, deltaY: Double, timestamp: TimeInterval) {\n        pendingInputX += deltaX\n        pendingInputY += deltaY\n        lastInputTimestamp = timestamp\n\n        if sessionState == .idle, deltaX != 0 || deltaY != 0 {\n            sessionState = .touching\n            touchHasBegun = false\n            pendingMomentumBegin = false\n        } else if sessionState == .momentum, deltaX != 0 || deltaY != 0 {\n            sessionState = .touching\n            touchHasBegun = false\n            pendingMomentumBegin = false\n            reengagedFromMomentum = true\n        }\n\n        if lastTickTimestamp == nil {\n            lastTickTimestamp = timestamp\n        }\n    }\n\n    func advance(to timestamp: TimeInterval) -> Emission? {\n        let previousTick = lastTickTimestamp ?? timestamp\n        let dt = (timestamp - previousTick).clamped(to: 1.0 / 240.0 ... 1.0 / 24.0)\n        lastTickTimestamp = timestamp\n\n        let hasPendingInput = pendingInputX != 0 || pendingInputY != 0\n        let hasFreshInput = lastInputTimestamp.map { timestamp - $0 <= inputGrace } ?? false\n        let shouldBlendMomentumReengagement = reengagedFromMomentum && hasPendingInput\n\n        let emissionX = advanceAxis(\n            behavior: horizontalBehavior,\n            pendingInput: &pendingInputX,\n            desiredVelocity: &desiredVelocityX,\n            velocity: &velocityX,\n            hasPendingInput: hasPendingInput,\n            hasFreshInput: hasFreshInput,\n            reengagedFromMomentum: shouldBlendMomentumReengagement,\n            dt: dt\n        )\n        let emissionY = advanceAxis(\n            behavior: verticalBehavior,\n            pendingInput: &pendingInputY,\n            desiredVelocity: &desiredVelocityY,\n            velocity: &velocityY,\n            hasPendingInput: hasPendingInput,\n            hasFreshInput: hasFreshInput,\n            reengagedFromMomentum: shouldBlendMomentumReengagement,\n            dt: dt\n        )\n        reengagedFromMomentum = false\n\n        let hasMovement = abs(emissionX) >= 0.01 || abs(emissionY) >= 0.01\n        let shouldContinueMomentum = abs(velocityX) > stopThreshold || abs(velocityY) > stopThreshold\n\n        switch sessionState {\n        case .idle:\n            return nil\n\n        case .touching:\n            if hasFreshInput {\n                guard hasMovement else {\n                    return nil\n                }\n\n                let phase: CGScrollPhase = touchHasBegun ? .changed : .began\n                touchHasBegun = true\n                return .init(\n                    deltaX: emissionX,\n                    deltaY: emissionY,\n                    phase: phase == .began ? .touchBegan : .touchChanged\n                )\n            }\n\n            if shouldContinueMomentum {\n                sessionState = .momentum\n                pendingMomentumBegin = true\n                touchHasBegun = false\n                return .init(deltaX: 0, deltaY: 0, phase: .touchEnded)\n            }\n\n            sessionState = .idle\n            velocityX = 0\n            velocityY = 0\n            desiredVelocityX = 0\n            desiredVelocityY = 0\n            touchHasBegun = false\n            return .init(deltaX: emissionX, deltaY: emissionY, phase: .touchEnded)\n\n        case .momentum:\n            guard hasMovement || shouldContinueMomentum else {\n                sessionState = .idle\n                velocityX = 0\n                velocityY = 0\n                desiredVelocityX = 0\n                desiredVelocityY = 0\n                touchHasBegun = false\n                pendingMomentumBegin = false\n                return .init(deltaX: 0, deltaY: 0, phase: .momentumEnded)\n            }\n\n            if pendingMomentumBegin {\n                pendingMomentumBegin = false\n                return .init(deltaX: emissionX, deltaY: emissionY, phase: .momentumBegan)\n            }\n\n            return .init(deltaX: emissionX, deltaY: emissionY, phase: .momentumChanged)\n        }\n    }\n\n    private func advanceAxis(\n        behavior: AxisBehavior,\n        pendingInput: inout Double,\n        desiredVelocity: inout Double,\n        velocity: inout Double,\n        hasPendingInput: Bool,\n        hasFreshInput: Bool,\n        reengagedFromMomentum: Bool,\n        dt: TimeInterval\n    ) -> Double {\n        switch behavior {\n        case .passthrough:\n            defer {\n                pendingInput = 0\n            }\n            return pendingInput\n\n        case let .smoothed(tuning):\n            if pendingInput != 0 {\n                desiredVelocity = reengagedFromMomentum\n                    ? tuning.reengagedDesiredVelocity(for: pendingInput, currentVelocity: velocity)\n                    : tuning.desiredVelocity(for: pendingInput)\n                if reengagedFromMomentum {\n                    let kick = tuning.reengagementKickFactor(\n                        desiredVelocity: desiredVelocity,\n                        currentVelocity: velocity\n                    )\n                    velocity += (desiredVelocity - velocity) * kick\n                }\n                pendingInput = 0\n            }\n\n            if hasFreshInput || hasPendingInput {\n                let blend = reengagedFromMomentum\n                    ? tuning.reengagementBlendFactor(\n                        for: dt,\n                        desiredVelocity: desiredVelocity,\n                        currentVelocity: velocity\n                    )\n                    : tuning.blendFactor(for: dt)\n                velocity += (desiredVelocity - velocity) * blend\n            } else {\n                velocity *= tuning.momentumDecay(for: dt)\n            }\n\n            return velocity * dt\n        }\n    }\n\n    private func axisIsActive(pendingInput: Double, desiredVelocity: Double, velocity: Double) -> Bool {\n        abs(pendingInput) >= axisActivityThreshold\n            || abs(desiredVelocity) >= axisActivityThreshold\n            || abs(velocity) >= axisActivityThreshold\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/SmoothedScrollingTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nfinal class SmoothedScrollingTransformer: EventTransformer, Deactivatable {\n    private static let log = OSLog(\n        subsystem: Bundle.main.bundleIdentifier!, category: \"SmoothedScrolling\"\n    )\n    private static let timerInterval: TimeInterval = 1.0 / 120.0\n    private let smoothed: Scheme.Scrolling.Bidirectional<Scheme.Scrolling.Smoothed>\n    private let now: () -> TimeInterval\n    private let eventSink: (CGEvent) -> Void\n    private let delivery = SmoothedScrollEventDelivery()\n\n    private var engine: SmoothedScrollingEngine\n    private var timer: EventThreadTimer?\n    private var lastFlags: CGEventFlags = []\n\n    init(\n        smoothed: Scheme.Scrolling.Bidirectional<Scheme.Scrolling.Smoothed>,\n        now: @escaping () -> TimeInterval = { ProcessInfo.processInfo.systemUptime },\n        eventSink: @escaping (CGEvent) -> Void = { $0.post(tap: .cgSessionEventTap) }\n    ) {\n        self.smoothed = smoothed\n        self.now = now\n        self.eventSink = eventSink\n        engine = SmoothedScrollingEngine(smoothed: smoothed)\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        guard event.type == .scrollWheel else {\n            return event\n        }\n\n        let view = ScrollWheelEventView(event)\n\n        if event.isLinearMouseSyntheticEvent {\n            return event\n        }\n\n        let deltaX = delivery.deltaXInPixels(from: view)\n        let deltaY = delivery.deltaYInPixels(from: view)\n        let hasNativePhase = view.scrollPhase != nil\n        let hasNativeMomentum = view.momentumPhase != .none\n\n        let smoothsX = smoothed.horizontal != nil\n        let smoothsY = smoothed.vertical != nil\n        let handlesX = smoothsX && deltaX != 0\n        let handlesY = smoothsY && deltaY != 0\n        let interceptsX = smoothsX && deltaX != 0\n        let interceptsY = smoothsY && deltaY != 0\n\n        if view.continuous, hasNativePhase || hasNativeMomentum {\n            return transformNativeContinuousGesture(\n                event,\n                view: view,\n                deltaX: deltaX,\n                deltaY: deltaY,\n                handlesX: handlesX,\n                handlesY: handlesY\n            )\n        }\n\n        guard interceptsX || interceptsY else {\n            return event\n        }\n\n        if handlesX || handlesY {\n            lastFlags = event.flags\n            if handlesX != handlesY {\n                engine.resetOtherAxis(ifExclusiveIncomingAxis: handlesX ? .horizontal : .vertical)\n            }\n            engine.feed(\n                deltaX: handlesX ? deltaX : 0,\n                deltaY: handlesY ? deltaY : 0,\n                timestamp: now()\n            )\n            startTimerIfNeeded()\n        }\n\n        let passthroughEvent = event.copy() ?? event\n        let passthroughView = ScrollWheelEventView(passthroughEvent)\n        if interceptsX {\n            delivery.zeroHorizontal(on: passthroughView)\n        }\n        if interceptsY {\n            delivery.zeroVertical(on: passthroughView)\n        }\n\n        return delivery.deltaXInPixels(from: passthroughView) == 0\n            && delivery.deltaYInPixels(from: passthroughView) == 0\n            ? nil\n            : passthroughEvent\n    }\n\n    func deactivate() {\n        stopTimer()\n        engine = SmoothedScrollingEngine(smoothed: smoothed)\n        lastFlags = []\n    }\n\n    private func startTimerIfNeeded() {\n        guard timer == nil else {\n            return\n        }\n\n        timer = EventThread.shared.scheduleTimer(\n            interval: Self.timerInterval,\n            repeats: true\n        ) { [weak self] in\n            self?.tick()\n        }\n    }\n\n    private func transformNativeContinuousGesture(\n        _ event: CGEvent,\n        view: ScrollWheelEventView,\n        deltaX: Double,\n        deltaY: Double,\n        handlesX: Bool,\n        handlesY: Bool\n    ) -> CGEvent? {\n        let interceptsX = smoothed.horizontal != nil\n        let interceptsY = smoothed.vertical != nil\n\n        guard interceptsX || interceptsY else {\n            return event\n        }\n\n        lastFlags = event.flags\n\n        if handlesX || handlesY {\n            if handlesX != handlesY {\n                engine.resetOtherAxis(ifExclusiveIncomingAxis: handlesX ? .horizontal : .vertical)\n            }\n            engine.feed(\n                deltaX: handlesX ? deltaX : 0,\n                deltaY: handlesY ? deltaY : 0,\n                timestamp: now()\n            )\n        }\n\n        if let emission = engine.advance(to: now()) {\n            delivery.apply(phases: delivery.phasesFor(emission.phase), to: view)\n\n            if interceptsX {\n                delivery.setHorizontal(handlesX ? emission.deltaX : 0, on: view)\n            }\n            if interceptsY {\n                delivery.setVertical(handlesY ? emission.deltaY : 0, on: view)\n            }\n        } else {\n            if interceptsX, !handlesX {\n                delivery.zeroHorizontal(on: view)\n            }\n            if interceptsY, !handlesY {\n                delivery.zeroVertical(on: view)\n            }\n        }\n\n        let shouldReset = view.scrollPhase == .ended || view.momentumPhase == .end\n        if shouldReset {\n            engine = SmoothedScrollingEngine(smoothed: smoothed)\n            stopTimer()\n        }\n\n        return event\n    }\n\n    private func stopTimer() {\n        timer?.invalidate()\n        timer = nil\n    }\n\n    func tick() {\n        guard let emission = engine.advance(to: now()) else {\n            if !engine.isRunning {\n                stopTimer()\n            }\n            return\n        }\n\n        post(emission: emission)\n\n        if !engine.isRunning {\n            stopTimer()\n        }\n    }\n\n    private func post(emission: SmoothedScrollingEngine.Emission) {\n        guard\n            let event = CGEvent(\n                scrollWheelEvent2Source: nil,\n                units: .pixel,\n                wheelCount: 2,\n                wheel1: 0,\n                wheel2: 0,\n                wheel3: 0\n            )\n        else {\n            return\n        }\n\n        let view = ScrollWheelEventView(event)\n        view.continuous = true\n        delivery.setHorizontal(emission.deltaX, on: view)\n        delivery.setVertical(emission.deltaY, on: view)\n        delivery.apply(phases: delivery.phasesFor(emission.phase), to: view)\n        event.isLinearMouseSyntheticEvent = true\n        event.flags = lastFlags\n        eventSink(event)\n\n        os_log(\n            \"post smoothed scroll deltaX=%{public}.3f deltaY=%{public}.3f phase=%{public}@ momentum=%{public}@\",\n            log: Self.log,\n            type: .info,\n            emission.deltaX,\n            emission.deltaY,\n            String(describing: view.scrollPhase),\n            String(describing: view.momentumPhase)\n        )\n    }\n}\n\nprivate struct SmoothedScrollEventDelivery {\n    private static let inputLineStepInPoints = 36.0\n    private static let outputLineStepInPoints = 12.0\n\n    func apply(\n        phases: (scrollPhase: CGScrollPhase?, momentumPhase: CGMomentumScrollPhase),\n        to view: ScrollWheelEventView\n    ) {\n        view.scrollPhase = phases.scrollPhase\n        view.momentumPhase = phases.momentumPhase\n    }\n\n    func phasesFor(_ phase: SmoothedScrollingEngine\n        .Phase) -> (scrollPhase: CGScrollPhase?, momentumPhase: CGMomentumScrollPhase) {\n        switch phase {\n        case .touchBegan:\n            return (.began, .none)\n        case .touchChanged:\n            return (.changed, .none)\n        case .touchEnded:\n            return (.ended, .none)\n        case .momentumBegan:\n            return (nil, .begin)\n        case .momentumChanged:\n            return (nil, .continuous)\n        case .momentumEnded:\n            return (nil, .end)\n        }\n    }\n\n    func deltaXInPixels(from view: ScrollWheelEventView) -> Double {\n        if !view.continuous {\n            if view.deltaX != 0 {\n                return Double(view.deltaX) * Self.inputLineStepInPoints\n            }\n            if view.deltaXPt != 0 {\n                return view.deltaXPt * Self.inputLineStepInPoints\n            }\n            if view.deltaXFixedPt != 0 {\n                return view.deltaXFixedPt * Self.inputLineStepInPoints * 10\n            }\n        }\n        if view.deltaXPt != 0 {\n            return view.deltaXPt\n        }\n        if view.deltaXFixedPt != 0 {\n            return view.deltaXFixedPt\n        }\n        return Double(view.deltaX) * Self.inputLineStepInPoints\n    }\n\n    func deltaYInPixels(from view: ScrollWheelEventView) -> Double {\n        if !view.continuous {\n            if view.deltaY != 0 {\n                return Double(view.deltaY) * Self.inputLineStepInPoints\n            }\n            if view.deltaYPt != 0 {\n                return view.deltaYPt * Self.inputLineStepInPoints\n            }\n            if view.deltaYFixedPt != 0 {\n                return view.deltaYFixedPt * Self.inputLineStepInPoints * 10\n            }\n        }\n        if view.deltaYPt != 0 {\n            return view.deltaYPt\n        }\n        if view.deltaYFixedPt != 0 {\n            return view.deltaYFixedPt\n        }\n        return Double(view.deltaY) * Self.inputLineStepInPoints\n    }\n\n    func setHorizontal(_ value: Double, on view: ScrollWheelEventView) {\n        view.deltaX = integerDelta(for: value)\n        view.deltaXPt = pointDelta(for: value)\n        view.deltaXFixedPt = value\n        view.ioHidScrollX = value\n    }\n\n    func setVertical(_ value: Double, on view: ScrollWheelEventView) {\n        view.deltaY = integerDelta(for: value)\n        view.deltaYPt = pointDelta(for: value)\n        view.deltaYFixedPt = value\n        view.ioHidScrollY = value\n    }\n\n    func zeroHorizontal(on view: ScrollWheelEventView) {\n        setHorizontal(0, on: view)\n    }\n\n    func zeroVertical(on view: ScrollWheelEventView) {\n        setVertical(0, on: view)\n    }\n\n    private func integerDelta(for value: Double) -> Int64 {\n        Int64((value / Self.outputLineStepInPoints).rounded(.towardZero))\n    }\n\n    private func pointDelta(for value: Double) -> Double {\n        guard value != 0 else {\n            return 0\n        }\n\n        return Double(Int64(value.rounded(.towardZero)))\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/SwitchPrimaryAndSecondaryButtonsTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\n\nclass SwitchPrimaryAndSecondaryButtonsTransformer {\n    static let log = OSLog(\n        subsystem: Bundle.main.bundleIdentifier!,\n        category: \"SwitchPrimaryAndSecondaryButtonsTransformer\"\n    )\n\n    init() {}\n}\n\nextension SwitchPrimaryAndSecondaryButtonsTransformer: EventTransformer {\n    func transform(_ event: CGEvent) -> CGEvent? {\n        let mouseEventView = MouseEventView(event)\n\n        guard var mouseButton = mouseEventView.mouseButton else {\n            return event\n        }\n\n        switch mouseButton {\n        case .left:\n            mouseButton = .right\n        case .right:\n            mouseButton = .left\n        default:\n            return event\n        }\n\n        mouseEventView.mouseButton = mouseButton\n        event.type = mouseButton.fixedCGEventType(of: event.type)\n        os_log(\n            \"Switched primary and secondary button: %{public}s\",\n            log: Self.log,\n            type: .info,\n            String(describing: mouseButton)\n        )\n\n        return event\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventTransformer/UniversalBackForwardTransformer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport GestureKit\nimport os.log\n\nclass UniversalBackForwardTransformer: EventTransformer {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"UniversalBackForward\")\n\n    private static let includes = [\n        \"com.apple.*\",\n        \"com.binarynights.ForkLift*\",\n        \"org.mozilla.firefox\",\n        \"com.operasoftware.Opera\"\n    ]\n\n    enum Replacement: Equatable {\n        case mouseButton(CGMouseButton)\n        case navigationSwipe(NavigationSwipeDirection)\n    }\n\n    enum NavigationSwipeDirection: Equatable {\n        case left\n        case right\n\n        var hidDirection: IOHIDSwipeMask {\n            switch self {\n            case .left:\n                return .swipeLeft\n            case .right:\n                return .swipeRight\n            }\n        }\n    }\n\n    private let universalBackForward: Scheme.Buttons.UniversalBackForward\n\n    init(universalBackForward: Scheme.Buttons.UniversalBackForward) {\n        self.universalBackForward = universalBackForward\n    }\n\n    static func interestedButtons(for universalBackForward: Scheme.Buttons.UniversalBackForward) -> Set<CGMouseButton> {\n        switch universalBackForward {\n        case .none:\n            return []\n        case .both:\n            return [.back, .forward]\n        case .backOnly:\n            return [.back]\n        case .forwardOnly:\n            return [.forward]\n        }\n    }\n\n    static func supportsTargetBundleIdentifier(_ bundleIdentifier: String?) -> Bool {\n        guard let bundleIdentifier else {\n            return false\n        }\n\n        return Self.includes.contains {\n            if $0.hasSuffix(\"*\") {\n                return bundleIdentifier.hasPrefix($0.dropLast())\n            }\n            return bundleIdentifier == $0\n        }\n    }\n\n    static func replacement(\n        for mouseButton: CGMouseButton,\n        universalBackForward: Scheme.Buttons.UniversalBackForward?,\n        targetBundleIdentifier: String?\n    ) -> Replacement {\n        guard let universalBackForward,\n              interestedButtons(for: universalBackForward).contains(mouseButton),\n              supportsTargetBundleIdentifier(targetBundleIdentifier) else {\n            return .mouseButton(mouseButton)\n        }\n\n        switch mouseButton {\n        case .back:\n            return .navigationSwipe(.left)\n        case .forward:\n            return .navigationSwipe(.right)\n        default:\n            return .mouseButton(mouseButton)\n        }\n    }\n\n    @discardableResult\n    static func postNavigationSwipeIfNeeded(\n        for mouseButton: CGMouseButton,\n        universalBackForward: Scheme.Buttons.UniversalBackForward?,\n        targetBundleIdentifier: String?\n    ) -> Bool {\n        guard case let .navigationSwipe(direction) = replacement(\n            for: mouseButton,\n            universalBackForward: universalBackForward,\n            targetBundleIdentifier: targetBundleIdentifier\n        ) else {\n            return false\n        }\n\n        guard let event = GestureEvent(\n            navigationSwipeSource: nil,\n            direction: direction.hidDirection\n        ) else {\n            return false\n        }\n\n        event.post(tap: .cgSessionEventTap)\n        return true\n    }\n\n    func transform(_ event: CGEvent) -> CGEvent? {\n        if event.isGestureCleanupRelease {\n            return event\n        }\n\n        let view = MouseEventView(event)\n        guard let mouseButton = view.mouseButton else {\n            return event\n        }\n\n        let targetBundleIdentifier = view.targetPid?.bundleIdentifier\n        let targetBundleIdentifierString = targetBundleIdentifier ?? \"(nil)\"\n        guard case let .navigationSwipe(direction) = Self.replacement(\n            for: mouseButton,\n            universalBackForward: universalBackForward,\n            targetBundleIdentifier: targetBundleIdentifier\n        ) else {\n            return event\n        }\n\n        // We'll simulate swipes when back/forward button down\n        // and eats corresponding mouse up events.\n        switch event.type {\n        case .otherMouseDown:\n            break\n        case .otherMouseUp:\n            return nil\n        default:\n            return event\n        }\n\n        os_log(\"Convert to swipe: %{public}@\", log: Self.log, type: .info, targetBundleIdentifierString)\n        GestureEvent(navigationSwipeSource: nil, direction: direction.hidDirection)?\n            .post(tap: .cgSessionEventTap)\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventView/EventView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nclass EventView {\n    let event: CGEvent\n\n    init(_ event: CGEvent) {\n        self.event = event\n    }\n\n    var modifierFlags: CGEventFlags {\n        get {\n            event.flags.intersection([.maskCommand, .maskShift, .maskAlternate, .maskControl])\n        }\n        set {\n            event.flags = event.flags\n                .subtracting([.maskCommand, .maskShift, .maskAlternate, .maskControl])\n                .union(newValue)\n        }\n    }\n\n    var modifiers: [String] {\n        [\n            (CGEventFlags.maskCommand, \"command\"),\n            (CGEventFlags.maskShift, \"shift\"),\n            (CGEventFlags.maskAlternate, \"option\"),\n            (CGEventFlags.maskControl, \"control\")\n        ]\n        .filter { modifierFlags.contains($0.0) }\n        .map(\\.1)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventView/MouseEventView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\n\nclass MouseEventView: EventView {\n    var mouseButton: CGMouseButton? {\n        get {\n            guard let mouseButtonNumber = UInt32(exactly: event.getIntegerValueField(.mouseEventButtonNumber)) else {\n                return nil\n            }\n            return CGMouseButton(rawValue: mouseButtonNumber)!\n        }\n\n        set {\n            guard let newValue else {\n                return\n            }\n\n            event.type = newValue.fixedCGEventType(of: event.type)\n            event.setIntegerValueField(.mouseEventButtonNumber, value: Int64(newValue.rawValue))\n        }\n    }\n\n    var mouseButtonDescription: String {\n        guard let mouseButton else {\n            return \"(nil)\"\n        }\n\n        return (modifiers + [\"<button \\(mouseButton.rawValue)>\"]).joined(separator: \"+\")\n    }\n\n    var sourcePid: pid_t? {\n        let pid = pid_t(event.getIntegerValueField(.eventSourceUnixProcessID))\n        guard pid > 0 else {\n            return nil\n        }\n        return pid\n    }\n\n    var targetPid: pid_t? {\n        let pid = pid_t(event.getIntegerValueField(.eventTargetUnixProcessID))\n        guard pid > 0 else {\n            return nil\n        }\n        return pid\n    }\n\n    var mouseLocationOwnerPid: pid_t? {\n        event.location.topmostWindowOwnerPid\n    }\n}\n"
  },
  {
    "path": "LinearMouse/EventView/ScrollWheelEventView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport os.log\nimport SceneKit\n\nclass ScrollWheelEventView: MouseEventView {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"ScrollWheelEventView\")\n\n    private let ioHidEvent: IOHIDEvent?\n\n    override init(_ event: CGEvent) {\n        assert(event.type == .scrollWheel)\n        ioHidEvent = CGEventCopyIOHIDEvent(event)\n        super.init(event)\n    }\n\n    var continuous: Bool {\n        get { event.getIntegerValueField(.scrollWheelEventIsContinuous) != 0 }\n        set { event.setIntegerValueField(.scrollWheelEventIsContinuous, value: newValue ? 1 : 0) }\n    }\n\n    var scrollPhase: CGScrollPhase? {\n        get {\n            let rawValue = UInt32(event.getIntegerValueField(.scrollWheelEventScrollPhase))\n            guard rawValue != 0 else {\n                return nil\n            }\n            return .init(rawValue: rawValue)\n        }\n        set {\n            event.setIntegerValueField(.scrollWheelEventScrollPhase, value: Int64(newValue?.rawValue ?? 0))\n        }\n    }\n\n    var momentumPhase: CGMomentumScrollPhase {\n        get {\n            .init(rawValue: UInt32(event.getIntegerValueField(.scrollWheelEventMomentumPhase))) ?? .none\n        }\n        set {\n            event.setIntegerValueField(.scrollWheelEventMomentumPhase, value: Int64(newValue.rawValue))\n        }\n    }\n\n    var syntheticMarker: Int64 {\n        get { event.getIntegerValueField(.eventSourceUserData) }\n        set { event.setIntegerValueField(.eventSourceUserData, value: newValue) }\n    }\n\n    var deltaX: Int64 {\n        get { event.getIntegerValueField(.scrollWheelEventDeltaAxis2) }\n        set { event.setIntegerValueField(.scrollWheelEventDeltaAxis2, value: newValue) }\n    }\n\n    var deltaXFixedPt: Double {\n        get { event.getDoubleValueField(.scrollWheelEventFixedPtDeltaAxis2) }\n        set { event.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis2, value: newValue) }\n    }\n\n    var deltaXPt: Double {\n        get { event.getDoubleValueField(.scrollWheelEventPointDeltaAxis2) }\n        set { event.setDoubleValueField(.scrollWheelEventPointDeltaAxis2, value: newValue) }\n    }\n\n    var deltaXSignum: Int64 {\n        continuous ? Int64(sign(deltaXPt)) : deltaX.signum()\n    }\n\n    var deltaY: Int64 {\n        get { event.getIntegerValueField(.scrollWheelEventDeltaAxis1) }\n        set { event.setIntegerValueField(.scrollWheelEventDeltaAxis1, value: newValue) }\n    }\n\n    var deltaYFixedPt: Double {\n        get { event.getDoubleValueField(.scrollWheelEventFixedPtDeltaAxis1) }\n        set { event.setDoubleValueField(.scrollWheelEventFixedPtDeltaAxis1, value: newValue) }\n    }\n\n    var deltaYPt: Double {\n        get { event.getDoubleValueField(.scrollWheelEventPointDeltaAxis1) }\n        set { event.setDoubleValueField(.scrollWheelEventPointDeltaAxis1, value: newValue) }\n    }\n\n    var deltaYSignum: Int64 {\n        continuous ? Int64(sign(deltaYPt)) : deltaY.signum()\n    }\n\n    var ioHidScrollX: Double {\n        get {\n            guard let ioHidEvent else {\n                return 0\n            }\n            return IOHIDEventGetFloatValue(ioHidEvent, kIOHIDEventFieldScrollX)\n        }\n        set {\n            guard let ioHidEvent else {\n                return\n            }\n            return IOHIDEventSetFloatValue(ioHidEvent, kIOHIDEventFieldScrollX, newValue)\n        }\n    }\n\n    var ioHidScrollY: Double {\n        get {\n            guard let ioHidEvent else {\n                return 0\n            }\n            return IOHIDEventGetFloatValue(ioHidEvent, kIOHIDEventFieldScrollY)\n        }\n        set {\n            guard let ioHidEvent else {\n                return\n            }\n            return IOHIDEventSetFloatValue(ioHidEvent, kIOHIDEventFieldScrollY, newValue)\n        }\n    }\n\n    var matrixValue: double2x4 {\n        double2x4(\n            [Double(deltaX), deltaXFixedPt, deltaXPt, ioHidScrollX],\n            [Double(deltaY), deltaYFixedPt, deltaYPt, ioHidScrollY]\n        )\n    }\n\n    func transform(matrix: double2x2) {\n        let oldValue = matrixValue\n        let newValue = oldValue * matrix\n        // In case that Int(deltaX), Int(deltaY) = 0 when 0 < abs(deltaX), abs(deltaY) < 0.5.\n        let deltaXY = newValue.transpose[0]\n        let normalizedDeltaXY = sign(deltaXY) * max(_simd_round_d2(abs(deltaXY)), [1, 1])\n        (deltaX, deltaXFixedPt, deltaXPt, ioHidScrollX) = (\n            Int64(normalizedDeltaXY.x),\n            newValue[0][1],\n            newValue[0][2],\n            newValue[0][3]\n        )\n        (deltaY, deltaYFixedPt, deltaYPt, ioHidScrollY) = (\n            Int64(normalizedDeltaXY.y),\n            newValue[1][1],\n            newValue[1][2],\n            newValue[1][3]\n        )\n        os_log(\n            \"transform: oldValue=%{public}@, matrix=%{public}@, newValue=%{public}@\",\n            log: Self.log,\n            type: .info,\n            String(describing: oldValue),\n            String(describing: matrix),\n            String(describing: newValue)\n        )\n    }\n\n    func swapXY() {\n        transform(matrix: .init([0, 1], [1, 0]))\n    }\n\n    func negate(vertically: Bool = false, horizontally: Bool = false) {\n        transform(matrix: .init([horizontally ? -1 : 1, 0], [0, vertically ? -1 : 1]))\n    }\n\n    func scale(factor: Double) {\n        scale(factorX: factor, factorY: factor)\n    }\n\n    func scale(factorX: Double = 1, factorY: Double = 1) {\n        transform(matrix: .init([factorX, 0], [0, factorY]))\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.utilities</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>LSUIElement</key>\n\t<true/>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>SUFeedURL</key>\n\t<string>https://linearmouse.app/appcast.xml</string>\n\t<key>SUScheduledCheckInterval</key>\n\t<integer>604800</integer>\n</dict>\n</plist>\n"
  },
  {
    "path": "LinearMouse/LinearMouse-Bridging-Header.h",
    "content": "//\n//  Touch-Bridging-Header.h\n//  LinearMouse\n//\n//  Created by lujjjh on 2021/8/5.\n//\n\n#include <CoreGraphics/CoreGraphics.h>\n#include <IOKit/hidsystem/IOHIDEventSystemClient.h>\n\n#include \"Utilities/Process.h\"\n\nCF_IMPLICIT_BRIDGING_ENABLED\n\nenum {\n    kIOHIDEventTypeNULL,\n    kIOHIDEventTypeVendorDefined,\n    kIOHIDEventTypeKeyboard = 3,\n    kIOHIDEventTypeRotation = 5,\n    kIOHIDEventTypeScroll = 6,\n    kIOHIDEventTypeZoom = 8,\n    kIOHIDEventTypeDigitizer = 11,\n    kIOHIDEventTypeNavigationSwipe = 16,\n    kIOHIDEventTypeForce = 32,\n};\ntypedef uint32_t IOHIDEventType;\ntypedef CFTypeRef IOHIDEventRef;\ntypedef double IOHIDFloat;\ntypedef uint32_t IOHIDEventField;\n\n#define IOHIDEventFieldBase(type) (type << 16)\n\n#define kIOHIDEventFieldScrollBase IOHIDEventFieldBase(kIOHIDEventTypeScroll)\nstatic const IOHIDEventField kIOHIDEventFieldScrollX = (kIOHIDEventFieldScrollBase | 0);\nstatic const IOHIDEventField kIOHIDEventFieldScrollY = (kIOHIDEventFieldScrollBase | 1);\n\nIOHIDEventRef CGEventCopyIOHIDEvent(CGEventRef);\nIOHIDEventType IOHIDEventGetType(IOHIDEventRef);\nIOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef, IOHIDEventField);\nvoid IOHIDEventSetFloatValue(IOHIDEventRef, IOHIDEventField, IOHIDFloat);\n\nCF_IMPLICIT_BRIDGING_DISABLED\n"
  },
  {
    "path": "LinearMouse/LinearMouse.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.files.user-selected.read-only</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "LinearMouse/LinearMouse.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nenum LinearMouse {\n    static var appBundleIdentifier: String {\n        Bundle.main.infoDictionary?[kCFBundleIdentifierKey as String] as? String ?? \"com.lujjjh.LinearMouse\"\n    }\n\n    static var appName: String {\n        Bundle.main.infoDictionary?[kCFBundleNameKey as String] as? String ?? \"(unknown)\"\n    }\n\n    static var appVersion: String {\n        Bundle.main.infoDictionary?[\"CFBundleShortVersionString\"] as? String ?? \"(unknown)\"\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Localizable.xcstrings",
    "content": "{\n  \"sourceLanguage\" : \"en\",\n  \"strings\" : {\n    \"- %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"- %@\"\n          }\n        }\n      }\n    },\n    \"(active)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktief)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(نشط)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktivno)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(actiu)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktivní)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktiv)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktiv)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ενεργό)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(activo)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktiivinen)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(actif)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(פעיל)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktív)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktif)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(attivo)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(有効)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(활성화됨)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(active)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktiv)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(actief)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktywne)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ativo)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(ativo)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(activ)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(активно)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktívne)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(активно)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktiv)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(aktif)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(активний)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(hoạt động)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(活跃)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"（使用中）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"(活躍)\"\n          }\n        }\n      }\n    },\n    \"%.1f pixel(s)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pikselsnelheid\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pikselsnelhede\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f بكسل\"\n                    }\n                  },\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f بكسل\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f بكسل\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f بكسل\"\n                    }\n                  },\n                  \"two\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f بكسل\"\n                    }\n                  },\n                  \"zero\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f بكسل\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksela\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksela\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f píxel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f píxels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixely\"\n                    }\n                  },\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixelů\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixelu\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixelů\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f Pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f Pixel\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f píxel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f píxeles\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pikseli\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pikseliä\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f פיקסלים\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f פיקסל\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f פיקסלים\"\n                    }\n                  },\n                  \"two\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f פיקסלים\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f képpont\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f képpont\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%.1f ピクセル\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f ピクセル\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f 픽셀\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksler\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksele\"\n                    }\n                  },\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pikseli\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksela\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixels\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixeli\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixeli\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пикселя\"\n                    }\n                  },\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пикселя\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пиксель\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пикселя\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixely\"\n                    }\n                  },\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixelov\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixelov\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksela\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksela\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pixlar\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f piksel\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f pikseller\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"few\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пікселі\"\n                    }\n                  },\n                  \"many\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пікселів\"\n                    }\n                  },\n                  \"one\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f піксель\"\n                    }\n                  },\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f пікселів\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f điểm ảnh\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f 像素\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f 畫素\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%#@value@\"\n          },\n          \"substitutions\" : {\n            \"value\" : {\n              \"formatSpecifier\" : \"f\",\n              \"variations\" : {\n                \"plural\" : {\n                  \"other\" : {\n                    \"stringUnit\" : {\n                      \"state\" : \"translated\",\n                      \"value\" : \"%.1f 畫素\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    },\n    \"%@ (%lld devices)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld toestelle)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld أجهزة)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld uređaja)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld dispositius)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld zařízení)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld enheder)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld Geräte)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld συσκευές)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld dispositivos)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld laitetta)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld appareils)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld מכשירים)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld eszköz)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld perangkat)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld dispositivi)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（%lld デバイス）\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld개 기기)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld စက်)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld enheter)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld apparaten)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld urządzeń)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld dispositivos)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld dispositivos)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld dispozitive)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld устройства)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld zariadení)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld uređaja)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld enheter)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld cihaz)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld пристроїв)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld thiết bị)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@（%lld 台设备）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld 部裝置)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ (%lld 部裝置)\"\n          }\n        }\n      }\n    },\n    \"%@ or below\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ of laer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ أو أقل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ili manje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ o menys\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ nebo méně\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ eller derunder\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ oder weniger\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ή λιγότερο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ o menos\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ tai alle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ou moins\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ או פחות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ vagy annál alacsonyabb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ atau kurang\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ o inferiore\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 以下\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 이하\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ သို့မဟုတ် အောက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ eller lavere\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ of lager\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ lub mniej\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ou inferior\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ou menos\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ sau mai puțin\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ или меньше\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ alebo menej\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ или мање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ eller lägre\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ veya altı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ або менше\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ trở xuống\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 或以下\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 或以下\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 或以下\"\n          }\n        }\n      }\n    },\n    \"%@ Settings…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Instellings…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ الإعدادات…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Postavke…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuració de %@…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Nastavení…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Indstillinger…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Einstellungen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Ρυθμίσεις…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Ajustes…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Asetukset…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Paramètres %@…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדרות %@…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ beállításai…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pengaturan %@…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impostazioni di %@…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 設定…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 설정…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ရဲ့ဆက်တင် …\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@-innstillinger…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ instellingen…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ustawienia %@…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Definições do %@…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Configurações…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Setări…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Настройки %@…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Nastavenia…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Поставке…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Inställningar…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Ayarları…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ Налаштування…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cài đặt %@…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 设置…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 設定…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 設定…\"\n          }\n        }\n      }\n    },\n    \"%1$@ (%2$@)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@（%2$@）\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@ (%2$@)\"\n          }\n        }\n      }\n    },\n    \"%d line(s)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d reël\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d reëls\"\n                }\n              }\n            }\n          }\n        },\n        \"ar\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d أسطر\"\n                }\n              },\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d أسطر\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d سطر\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d أسطر\"\n                }\n              },\n              \"two\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d أسطر\"\n                }\n              },\n              \"zero\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d أسطر\"\n                }\n              }\n            }\n          }\n        },\n        \"bs\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linija\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linija\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linija\"\n                }\n              }\n            }\n          }\n        },\n        \"ca\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d línia\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d línies\"\n                }\n              }\n            }\n          }\n        },\n        \"cs\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d řádky\"\n                }\n              },\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d řádků\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d řádek\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d řádků\"\n                }\n              }\n            }\n          }\n        },\n        \"da\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linje\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linjer\"\n                }\n              }\n            }\n          }\n        },\n        \"de\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d Zeile\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d Zeilen\"\n                }\n              }\n            }\n          }\n        },\n        \"el\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d γραμμή\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d γραμμές\"\n                }\n              }\n            }\n          }\n        },\n        \"en\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d line\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d lines\"\n                }\n              }\n            }\n          }\n        },\n        \"es\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d línea\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d líneas\"\n                }\n              }\n            }\n          }\n        },\n        \"fi\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d rivi\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d riviä\"\n                }\n              }\n            }\n          }\n        },\n        \"fr\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d ligne\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d lignes\"\n                }\n              }\n            }\n          }\n        },\n        \"he\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d שורות\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d שורה\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d שורות\"\n                }\n              },\n              \"two\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d שורות\"\n                }\n              }\n            }\n          }\n        },\n        \"hu\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d sor\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d sor\"\n                }\n              }\n            }\n          }\n        },\n        \"id\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d baris\"\n                }\n              }\n            }\n          }\n        },\n        \"it\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linea\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linee\"\n                }\n              }\n            }\n          }\n        },\n        \"ja\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d 行\"\n                }\n              }\n            }\n          }\n        },\n        \"ko\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d줄\"\n                }\n              }\n            }\n          }\n        },\n        \"my\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"လိုင်း %dလိုင်း\"\n                }\n              }\n            }\n          }\n        },\n        \"nb-NO\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linje\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linjer\"\n                }\n              }\n            }\n          }\n        },\n        \"nl\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d regel\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d regel\"\n                }\n              }\n            }\n          }\n        },\n        \"pl\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linie\"\n                }\n              },\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linii\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linia\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linii\"\n                }\n              }\n            }\n          }\n        },\n        \"pt\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linha\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linhas\"\n                }\n              }\n            }\n          }\n        },\n        \"pt-BR\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linha\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linhas\"\n                }\n              }\n            }\n          }\n        },\n        \"ro\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linii\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linie\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linii\"\n                }\n              }\n            }\n          }\n        },\n        \"ru\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d линии\"\n                }\n              },\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d линии\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d линия\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d линии\"\n                }\n              }\n            }\n          }\n        },\n        \"sk\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d riadky\"\n                }\n              },\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d riadkov\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d riadok\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d riadkov\"\n                }\n              }\n            }\n          }\n        },\n        \"sr\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linija\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linija\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d linija\"\n                }\n              }\n            }\n          }\n        },\n        \"sv\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d rad\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d rader\"\n                }\n              }\n            }\n          }\n        },\n        \"tr\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d satır\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d satırlar\"\n                }\n              }\n            }\n          }\n        },\n        \"uk\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"few\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d лінії\"\n                }\n              },\n              \"many\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d ліній\"\n                }\n              },\n              \"one\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d лінія\"\n                }\n              },\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d ліній\"\n                }\n              }\n            }\n          }\n        },\n        \"vi\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d dòng\"\n                }\n              }\n            }\n          }\n        },\n        \"zh-Hans\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d 行\"\n                }\n              }\n            }\n          }\n        },\n        \"zh-Hant\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d 行\"\n                }\n              }\n            }\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"variations\" : {\n            \"plural\" : {\n              \"other\" : {\n                \"stringUnit\" : {\n                  \"state\" : \"translated\",\n                  \"value\" : \"%d 行\"\n                }\n              }\n            }\n          }\n        }\n      }\n    },\n    \"%lld pixels\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pikselsnelhede\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld بكسل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld piksel\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld píxels\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixelů\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixels\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld Pixel\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixel\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld píxeles\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pikseliä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixels\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld פיקסלים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld képpont\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld piksel\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixel\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld ピクセル\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld픽셀\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixels\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld piksler\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixels\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pikseli\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld píxeis\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixels\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixeli\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld пикселей\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixelov\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld piksela\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixlar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld piksel\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld пікселів\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld pixel\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld 像素\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld 像素\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%lld 像素\"\n          }\n        }\n      }\n    },\n    \"⇧ (Shift)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Skuif)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Majúscules)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Umschalttaste)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Mayúsculas)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Vaihto)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Maj)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Maiusc)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Skift)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⇧ (Shift)\"\n          }\n        }\n      }\n    },\n    \"⌃ (Control)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Beheer)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Steuerung)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Ohjaus)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Contrôle)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃ (Control)\"\n          }\n        }\n      }\n    },\n    \"⌘ (Command)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Opdrag)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Comanda)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Befehl)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Comando)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Komento)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Comando)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Comando)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌘ (Command)\"\n          }\n        }\n      }\n    },\n    \"⌥ (Option)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Opsie)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Opció)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Wahltaste)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Opción)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Valinta)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Opzione)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Opção)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌥ (Option)\"\n          }\n        }\n      }\n    },\n    \"▾\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"▾\"\n          }\n        }\n      }\n    },\n    \"Accelerated\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versnel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مُسرّع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzano\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrychlené\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelereret\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beschleunigt\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιταχυνόμενη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acelerado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nopeutettu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accéléré\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מואץ\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gyorsított\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dipercepat\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加速\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"가속\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမြန်မြှင့်တင်ပြီးသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akselerert\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versneld\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przyspieszone\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acelerado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acelerado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ускоренное\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrýchlené\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Убрзано\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Påskynda\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İvmeli\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прискорений\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng tốc\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"带加速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"帶加速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"帶加速度\"\n          }\n        }\n      }\n    },\n    \"Action\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aksie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إجراء\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Funkcija\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acció\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Úkon\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Handling\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktion\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενέργεια\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acción\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toiminto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Action\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"פעולה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Művelet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tindakan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Azione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"動作\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"동작\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လုပ်ဆောင်ချက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Handling\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akcja\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ação\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acțiune\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Действие\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akcia\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Акција\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Åtgärd\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eylem\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дія\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hành động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"动作\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"動作\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"動作\"\n          }\n        }\n      }\n    },\n    \"Adaptive\" : {\n      \"comment\" : \"Preset label for scroll feel. Means the app adapts the response automatically based on input movement.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanpasbaar\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكيفي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prilagodljivo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptatiu\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptivní\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptiv\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptiv\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Προσαρμοστικό\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptativo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mukautuva\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptatif\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אדפטיבי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptív\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptif\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adattivo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アダプティブ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"적응형\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptiv\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptief\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptacyjne\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptativo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptável\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptiv\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Адаптивное\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptívne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Адаптивно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adaptiv\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uyarlanabilir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Адаптивне\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thích ứng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自适应\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動適應\"\n          }\n        }\n      }\n    },\n    \"All Apps\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle Programme\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"كل التطبيقات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sve aplikacije\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Totes les aplicacions\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Všechny aplikace\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle Apps\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle Anwendungen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Όλες τις Εφαρμογές\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas las aplicaciones\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaikki sovellukset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toutes les applis\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כל האפליקציות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Összes alkalmazás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Semua Aplikasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tutte le App\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"全てのアプリ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 앱\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အက်ပ်ပလီကေးရှင်း များအားလုံး\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle apper\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle apps\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wszystkie aplikacje\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todos os Apps\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todos os apps\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toate aplicațiile\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Все приложения\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Všetky aplikácie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Све апликације\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alla appar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tüm Uygulamalar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Усі застосунки\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tất cả ứng dụng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有应用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有程式\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有程式\"\n          }\n        }\n      }\n    },\n    \"All Displays\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle skerms\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"كل الشاشات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Svi ekrani\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Totes les pantalles\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Všechny displeje\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle skærme\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle Bildschirme\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Όλες οι οθόνες\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas las pantallas\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaikki näytöt\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tous les écrans\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כל התצוגות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Minden kijelző\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Semua Layar\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tutti i display\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"すべてのディスプレイ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모든 디스플레이\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Screens များအားလုံး\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle skjermer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alle schermen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wszystkie wyświetlacze\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todos os Monitores\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Todas as telas\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toate ecranele\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Все экраны\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Všetky displeje\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сви екрани\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alla skärmar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tüm Ekranlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Всі дисплеї\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tất cả Màn hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有显示器\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有顯示器\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"所有顯示器\"\n          }\n        }\n      }\n    },\n    \"Alter orientation\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verander oriëntasie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تغيير الاتجاه\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Promjeni orijentaciju\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alterar orientació\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Změna oriantace\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skift retning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollorientierung ändern\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τροποποίηση προσανατολισμού\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alter orientation\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambiar orientación\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muuta suuntaa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altérer l'orientation\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שנה כיוון גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Orientáció módosítása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubah orientasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambia direzione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"方向を変更する\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"방향 변경\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လမ်းကြောင်းပြောင်းရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endre orientering\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wijzig oriëntatie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmień orientację\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alterar orientação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mudar orientação\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifică orientarea\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Изменить направление прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmeniť orientáciu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Промени оријентацију\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ändra orientering\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yönlendirmeyi değiştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Змінити орієнтацію\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hoán đổi hướng cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"改变方向\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"改變方向\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"改變方向\"\n          }\n        }\n      }\n    },\n    \"Always show\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys altyd\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار دائمًا\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uvijek prikaži\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra sempre\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vždy zobrazit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis altid\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Immer anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση πάντα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar siempre\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä aina\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toujours afficher\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג תמיד\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mindig megjelenít\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selalu tampilkan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra sempre\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"常に表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"항상 보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမြဲတမ်းပြပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis alltid\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altijd tonen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zawsze pokazuj\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar sempre\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sempre mostrar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișare permanentă\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Всегда показывать\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vždy zobraziť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увек прикажи\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa alltid\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Her zaman göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Завжди показувати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Luôn hiển thị\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"始终显示\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"永遠顯示\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"永遠顯示\"\n          }\n        }\n      }\n    },\n    \"App Expose\" : {\n      \"comment\" : \"macOS feature name. Use the official localized system term if the target language has one.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Expose\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposar\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Expose\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exposição de Apps\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uygulama Gösterimi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"应用程序总览\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"App Exposé\"\n          }\n        }\n      }\n    },\n    \"Application windows\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programvensters\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نوافذ التطبيق\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prozori aplikacije\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finestres de l'aplicació\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okna aplikací\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programvinduer\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anwendungsfenster\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Παράθυρα εφαρμογής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ventanas de la aplicación\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sovellusikkunat\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fenêtre d'application\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"חלון האפליקציה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alkalmazásablakok\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jendela aplikasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finestre dell'applicazione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アプリケーションウィンドウ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"응용 프로그램 윈도우\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အက်ပ်ပလီကေးရှင်း ၏ ဝင်းဒိုးများ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programvinduer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toepassingsvenster\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okna aplikacji\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Janelas da aplicação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Janelas de aplicação\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ferestrele aplicațiilor\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Окна программы\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okno aplikácie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прозори апликација\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Programfönster\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uygulama pencereleri\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вікна застосунків\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cửa sổ ứng dụng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"应用程序窗口\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"應用程式視窗\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"應用程式視窗\"\n          }\n        }\n      }\n    },\n    \"Assign actions to mouse buttons\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys aksies toe aan muisknoppies\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تعيين إجراءات لأزرار الماوس\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podesi funkcije na dugmad miša\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Assigna accions als botons del ratolí\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přidělit akce tlačítkům myši\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tildel handlinger til museknapper\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maustasten Aktionen zuweisen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ανάθεση ενεργειών σε κουμπιά του ποντικιού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Asignar acciones a los botones del ratón\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määritä toimintoja hiiren painikkeisiin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Assigner des actions aux boutons de la souris\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שייך פעולות ללחצני העכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Műveletek hozzárendelése az egérgombokhoz\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tetapkan tindakan ke tombol mouse\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Assegna azioni ai pulsanti del mouse\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"マウスボタンに操作を割り当てる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"마우스 버튼에 동작 할당\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse ခလုတ်များကို လုပ်ဆောင်ချက်များ သတ်မှတ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilordne handlinger til museknapper\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acties toewijzen aan de muisknoppen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przypisz akcje do przycisków myszy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atribuir ações aos botões do rato\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atribuir ações para os botões do mouse\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atribuie acțiuni butoanelor mouse-ului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назначить действия на кнопки мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Priradiť akcie tlačidlám myši\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodeli akcije dugmadima miša\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilldela åtgärder till musknappar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fare düğmelerine eylem ata\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Призначити дії для клавіш миші\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gán hành động cho các nút chuột\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分配鼠标按钮的动作\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分配滑鼠按鈕的動作\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"分配滑鼠按鈕的動作\"\n          }\n        }\n      }\n    },\n    \"Assigning an action to the left button without any modifier keys is not allowed.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Om 'n aksie aan die linkerknoppie toe te wys sonder enige wysigingsleutels is nie toegelaat nie.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لا يُسمح بتعيين إجراء للزر الأيسر بدون أي مفاتيح تعديل.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodjeljivanje funkcije lijevom dugmetu bez modifikatorskih tipki nije dozvoljeno.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No es pot assignar una acció al botó esquerre sense cap tecla modificadora.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přiřadit úkon levému tlačítku bez modifikačních kláves není dovoleno.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tildeling af en handling til venstre knap uden ændringstaster er ikke tilladt.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die Zuweisung einer Aktion an die linke Maustaste ist ohne Modifikatortasten nicht zulässig.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Η ανάθεση μιας ενέργειας στο αριστερό πλήκτρο χωρίς πλήκτρα τροποποίησης δεν επιτρέπεται.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No se permite asignar una acción al botón izquierdo sin ninguna tecla modificadora.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toiminnon määrittäminen vasempaan painikkeeseen ilman muokkausnäppäimiä ei ole sallittua.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"L'attribution d'une action au bouton gauche sans aucune touche de modification n'est pas autorisée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שיוך של פעולה ללחצן העכבר השמאלי ללא מקשי שינוי אינו אפשרי.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egy művelet hozzárendelése a bal gombhoz módosítóbillentyűk nélkül nem megengedett.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menetapkan tindakan ke tombol kiri tanpa tombol pengubah tidak diperbolehkan.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"L'assegnazione di un'azione al pulsante sinistro, senza alcun tasto modificatore, non è consentita.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"修飾キーなしでアクションを左ボタンに割り当てることはできません。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"보조 키 없이 주요 버튼에 동작을 설정하는 것은 허용되지 않습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘယ်ဘက်ခလုတ်ကို modifier keys မရှိဘဲ လုပ်ဆောင်ခြင်းကို ခွင့်မပြုပါ။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Det er ikke tillatt å tilordne en handling til venstre knapp uten modifikasjonstaster.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Een actie toewijzen aan de linker knop zonder aanpassingstoets is niet toegestaan.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przypisywanie akcji do lewego przycisku myszy bez jakichkolwiek klawiszy modyfikujących jest niedozwolone.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não é permitido atribuir uma ação ao botão esquerdo sem teclas modificadoras.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não é permitido atribuir uma ação para o botão esquerdo sem nenhuma tecla modificadora.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nu este permisă atribuirea unei acțiuni butonului stânga fără nicio tastă modificatoare.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назначение стандартного действия на левую кнопку мыши не допускается.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Priradenie akcie ľavému tlačidlu bez modifikačných klávesov nie je povolené.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dodela akcije levom dugmetu bez modifikatora nije dozvoljena.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Det är inte tillåtet att tilldela en åtgärd till vänster knapp utan några modifieringstangenter.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herhangi bir değiştirici tuş olmadan sol düğmeye atama yapılamaz.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Присвоєння дії лівій кнопці без будь-яких клавіш-модифікаторів не допускається.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không được phép gán một hành động cho nút bên trái mà không có bất kỳ phím bổ trợ nào.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不能将动作分配给左键且不加修饰键。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將動作分配給左鍵必須加變更鍵。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不能將動作分配給左鍵且不加變更鍵。\"\n          }\n        }\n      }\n    },\n    \"auto\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"outo\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تلقائي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automatski\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automàtic\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automaticky\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automatisch\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αυτόματο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automaattinen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אוטומטי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automatikus\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"otomatis\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automatico\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"자동\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automatisch\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automático\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automático\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"automat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"авто\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ауто\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"auto\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"otomatik\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"авто\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"tự động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動\"\n          }\n        }\n      }\n    },\n    \"Auto switch to the active device\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skakel outomaties oor na die aktiewe toestel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التبديل التلقائي إلى الجهاز النشط\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatski prebaci na aktivni uređaj\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Commuta automàticament al dispositiu actiu\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaticky přepínat na aktivní zařízení\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skift automatisk til den aktive enhed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatisch zum aktiven Gerät wechseln\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αυτόματη μετάβαση στην ενεργή συσκευή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambiar automáticamente al dispositivo activo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaattinen vaihto aktiiviseen laitteeseen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Basculer automatiquement vers le périphérique actif\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלף אוטומטית למכשיר הפעיל\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatikus váltás az aktív eszközre\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beralih otomatis ke perangkat yang aktif\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Passa automaticamente al dispositivo attivo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動的に使用中のデバイスに切り替え\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"활성화된 장치로 자동 전환\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလုပ်လုပ်နေသော device ကို အလိုအလျောက် ပြောင်းရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bytt automatisk til den aktive enheten\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schakel automatisch naar het actieve apparaat\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatycznie przełącz na aktywne urządzenie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mudar automaticamente para o dispositivo ativo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alternar automaticamente para o dispositivo ativo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Comutare automată la dispozitivul activ\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автоматическое переключение на активное устройство\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaticky prepnúť na aktívne zariadenie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatsko prebacivanje na aktivni uređaj\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Växla automatiskt till den aktiva enheten\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otomatik olarak aktif cihaza değiştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автоматично перемикати на активний пристрій\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tự động chuyển qua thiết bị hoạt động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自动切换到活跃设备\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動切換到正在使用的設備\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動切換到活躍設備\"\n          }\n        }\n      }\n    },\n    \"Automatically follow the device that is currently active.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volg outomaties die toestel wat tans aktief is.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اتبع تلقائيًا الجهاز النشط حاليًا.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatski prati trenutno aktivni uređaj.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Segueix automàticament el dispositiu que està actiu actualment.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaticky sledovat aktuálně aktivní zařízení.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Følg automatisk den enhed, der er aktiv i øjeblikket.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Folgt automatisch dem gerade aktiven Gerät.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ακολουθεί αυτόματα τη συσκευή που είναι ενεργή.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sigue automáticamente el dispositivo que está activo actualmente.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seuraa automaattisesti laitetta, joka on tällä hetkellä aktiivinen.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivre automatiquement l’appareil actuellement actif.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"עקוב אוטומטית אחר המכשיר הפעיל כעת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatikus követés az éppen aktív eszközön.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ikuti secara otomatis perangkat yang sedang aktif.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Segui automaticamente il dispositivo attualmente attivo.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"現在アクティブなデバイスを自動的に追跡します。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"현재 활성화된 기기를 자동으로 따릅니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လက်ရှိအသက်ဝင်နေသော စက်ကို အလိုအလျောက် လိုက်နာပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Følg automatisk enheten som er aktiv for øyeblikket.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volg automatisch het apparaat dat momenteel actief is.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatycznie podążaj za aktualnie aktywnym urządzeniem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siga automaticamente o dispositivo que está ativo no momento.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siga automaticamente o dispositivo que está ativo no momento.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Urmărește automat dispozitivul activ în prezent.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автоматически следовать за активным устройством.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaticky sledovať aktuálne aktívne zariadenie.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatski prati uređaj koji je trenutno aktivan.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Följ automatiskt den enhet som är aktiv för tillfället.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Şu anda aktif olan aygıtı otomatik olarak izle.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автоматично відстежувати активний пристрій.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tự động theo dõi thiết bị hiện đang hoạt động.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自动跟随当前激活的设备。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動追蹤目前作用中的裝置。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動追蹤目前作用中的裝置。\"\n          }\n        }\n      }\n    },\n    \"Back\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terug\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"رجوع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazad\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enrere\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zpět\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilbage\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zurück\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πίσω\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volver\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Takaisin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Précédent\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אחורה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vissza\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kembali\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indietro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"戻る\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"뒤로 가기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နောက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilbake\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terug\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wstecz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voltar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voltar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Înapoi\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назад\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Späť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nazad\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tillbaka\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geri\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назад\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quay Lại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"后退\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"後退\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"後退\"\n          }\n        }\n      }\n    },\n    \"Back button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terugknoppie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"زر الرجوع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dugme za nazad\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botó enrere\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačítko Zpět\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilbage-knap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zurück-Taste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κουμπί Επιστροφής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botón atrás\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Takaisin-painike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bouton Précédent\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחצן חזור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vissza gomb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol kembali\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsante Indietro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"戻るボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"뒤로 가기 버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြန်ထွက်သည့် ခလုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilbake-knapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terug knop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przycisk wstecz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão Retroceder\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão Voltar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buton Înapoi\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопка Назад\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačidlo Späť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dugme za povratak\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bakåtknapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geri tuşu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопка «Назад»\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút Quay lại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"返回键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"返回鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"返回鍵\"\n          }\n        }\n      }\n    },\n    \"Balanced ramp-up and release.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebalanseerde opbou en afname.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تصاعد وخفوت متوازنان.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uravnotežen porast i otpuštanje.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Augment i alliberament equilibrats.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyvážený náběh a uvolnění.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afbalanceret opbygning og frigivelse.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausgewogener Anstieg und Auslauf.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ισορροπημένη επιτάχυνση και αποδέσμευση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumento y liberación equilibrados.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tasapainoinen kiihtyminen ja vapautus.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Montée et relâchement équilibrés.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"עלייה ושחרור מאוזנים.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiegyensúlyozott felfutás és lecsengés.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Peningkatan dan pelepasan yang seimbang.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione e rilascio bilanciati.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立ち上がりと抜けがバランスよくまとまっています。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"가속과 풀림이 균형 잡혀 있습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အရှိန်တက်မှုနှင့် ပြန်လျော့မှု မျှတသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balansert oppbygging og avslutning.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebalanceerde opbouw en uitloop.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrównoważone narastanie i wyhamowanie.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e libertação equilibradas.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e soltura equilibradas.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare și eliberare echilibrate.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сбалансированный разгон и спад.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyvážené zrýchlenie a uvoľnenie.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Уравнотежено убрзање и отпуштање.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balanserad uppbyggnad och avklingning.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dengeli hızlanma ve bırakış.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Збалансовані розгін і спад.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng tốc và nhả ra cân bằng.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加速与释放均衡。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加速與釋放均衡。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加速與釋放均衡。\"\n          }\n        }\n      }\n    },\n    \"Batteries\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterye\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"البطاريات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterije\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Piles\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterie\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterier\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterien\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μπαταρίες\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterías\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Paristot\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batteries\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סוללות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akkumulátorok\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterai\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterie\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"バッテリー\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"배터리\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘက်ထရီများ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterier\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterijen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterias\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterias\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterii\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Аккумуляторы\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batérie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterije\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterier\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Piller\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Акумулятори\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pin\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"电池\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"電池\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"電池\"\n          }\n        }\n      }\n    },\n    \"Battery %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batteryvlak %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"البطارية %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterija %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bateria %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterie %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batteri %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterie %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μπαταρία %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batería %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akku %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterie %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סוללה %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akkumulátor %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterai %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batteria %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"バッテリー %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"배터리 %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘက်ထရီ %@\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batteri %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batterij %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bateria %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bateria %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bateria %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baterie %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Батарея %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batéria %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Батерија %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batteri %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pil %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Акумулятор %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pin %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"电量 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"電量 %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"電量 %@\"\n          }\n        }\n      }\n    },\n    \"Bug report\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Foutverslag\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تقرير خطأ\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prijavi problem\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Informe d'error\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nahlášení chyby\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fejlrapport\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fehler melden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αναφορά σφάλματος\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Informe de error\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Virheraportti\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Signaler un bug\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"דיווח על באג\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hibajelentés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Laporan bug\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Segnalazione di bug\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"問題を報告\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버그 보고\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bug အစီရင်ခံစာ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Feilrapport\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bug rapporteren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zgłaszanie błędów\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Relatório de erro\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reportar bug\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Raportați probleme\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сообщить об ошибке\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nahlásenie chyby\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izveštaj o grešci\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Felrapport\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hata bildir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сповістити про помилку\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Báo cáo lỗi\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bug 反馈\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bug 回報\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bug 報告\"\n          }\n        }\n      }\n    },\n    \"Button #%lld click\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knoppie #%lld klik\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"النقر على الزر #%lld\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik #%lld dugme\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic del botó núm. %lld\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutí tlačítka #%lld\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik på knappen #%lld\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Taste #%lld drücken\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κουμπί #%lld κλικ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic botón #%lld\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Painike #%lld napsautus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic du bouton #%lld\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כפתור #%lld נלחץ\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gomb #%lld kattintás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik tombol #%lld\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic del pulsante numero %lld\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ボタン #%lld クリック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버튼 #%lld 클릭\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ခလုတ် %lld ၏ လုပ်ဆောင်ချက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knapp #%lld-klikk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knop #%lld klik\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknięcie przycisku #%lld\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique do botão #%lld\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique do botão #%lld\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apăsare buton #%lld\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нажатие #%lld\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik tlačidlom č.%lld\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik dugmeta #%lld\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knapp #%lld klick\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"#%lld Düğme tıklaması\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клац кнопки №%lld\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút nhấn #%lld\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按键 #%lld 点击\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按鍵 #%lld 點擊\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按鍵 #%lld 點擊\"\n          }\n        }\n      }\n    },\n    \"Buttons\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knoppies\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الأزرار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dugmad\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botons\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačítka\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knapper\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tasten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πλήκτρα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botones\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Painikkeet\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Boutons\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כפתורים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gombok\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol-tombol\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsanti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ခလုတ်များ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knapper\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knoppen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przyciski\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botões\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botões\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Butoane\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačidlá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дугмад\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knappar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tuşlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клавіші\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按钮\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按鈕\"\n          }\n        }\n      }\n    },\n    \"By Lines\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per Lyne\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حسب الأسطر\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prema linijama\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per línies\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po Řádcích\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Efter Linjer\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In Zeilen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ανά Γραμμές\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Por líneas\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Riveittäin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Par lignes\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לפי שורות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sorok szerint\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per Baris\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per riga\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"行\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"줄\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lines အလိုက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etter linjer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per regel\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po liniach\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Por Linhas\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Por linhas\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"După linii\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"По строкам\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podľa riadkov\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po linijama\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Efter rader\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Satıra göre\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"За Рядками\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Theo hàng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按行\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按行\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按行\"\n          }\n        }\n      }\n    },\n    \"By Pixels\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per Piksels\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حسب البكسلات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prema pikselima\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per píxels\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po Pixelech\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Efter Pixels\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In Pixel\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ανά Πίξελ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Por píxeles\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pikseleittäin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Par pixels\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לפי פיקסלים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Képpontok szerint\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per Piksel\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per pixel\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ピクセル数\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"픽셀\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pixels အလိုက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etter piksler\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per pixel\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po pikselach\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Por Píxeis\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Por pixels\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"De pixeli\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"По пикселям\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podľa pixelov\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po pikselima\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Av Pixlar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Piksele göre\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"За Пікселями\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Theo điểm ảnh\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按像素\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按畫素\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按像素\"\n          }\n        }\n      }\n    },\n    \"Bypass events from other applications\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omseil gebeurtenisse van ander toepassings\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تجاوز الأحداث من التطبيقات الأخرى\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Preskoči događaje od ostalih aplikacija\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora els esdeveniments d'altres aplicacions\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obejít události z ostatních aplikací\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omgå begivenheder fra andre applikationer\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ereignisse von anderen Anwendungen ignorieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Παράκαμψη συμβάντων από άλλες εφαρμογές\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Evitar eventos de otras aplicaciones\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ohita muiden sovellusten tapahtumat\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Éviter les événements d'autres applications\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"עקוף אירועים משאר האפליקציות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Események megkerülése más alkalmazásokból\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lewati peristiwa dari aplikasi lain\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora gli eventi da altre applicazioni\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"他のアプリケーションからイベントをバイパスする\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다른 앱에서 보낸 이벤트 제외\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တခြား အက်ပ်ပလီကေးရှင်း များမှ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer hendelser fra andre programmer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instellingen van andere toepassingen negeren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomiń zdarzenia z innych aplikacji\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar eventos de outras aplicações\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sobreponha eventos de outras aplicações\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoră evenimentele de la alte aplicații\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Допускать события из других приложений\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorovať udalosti z iných aplikácií\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zaobiđi događaje iz drugih aplikacija\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hoppa över händelser från andra program\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diğer uygulamalardan gelen olayları yoksay\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Обхід подій з інших застосунків\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bỏ qua sự kiện từ các ứng dụng khác\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不处理来自其他应用程序的事件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不處理來自其他應用程式的事件\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不處理來自其他應用程式的事件\"\n          }\n        }\n      }\n    },\n    \"Cancel\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kanselleer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إلغاء\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otkaži\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancel·la\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrušit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annuller\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abbrechen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ακύρωση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Peruuta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annuler\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ביטול\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mégse\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Batalkan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annulla\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"취소\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မလုပ်တော့ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avbryt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annuleren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anuluj\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cancelar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отмена\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrušiť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otkaži\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avbryt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vazgeç\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скасувати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Huỷ bỏ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"取消\"\n          }\n        }\n      }\n    },\n    \"Change speed\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verander spoed\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تغيير السرعة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Promijeni brzinu\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Canvia la velocitat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Změna rychlosti\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ændr hastighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollgeschwindigkeit ändern\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αλλαγή ταχύτητας\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Change speed\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambiar velocidad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muuta nopeutta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Changer la vitesse\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שנה מהירות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sebesség módosítása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubah kecepatan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cambia velocità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"速度変更\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"속도 변경\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အရှိန်ပြောင်းရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endre hastighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verander snelheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmień szybkość\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alterar velocidade\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alterar velocidade\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schimbă viteza\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Изменить скорость\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmeniť rýchlosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Promeni brzinu\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ändra hastighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hızı değiştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Змінити швидкість\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thay đổi tốc độ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"变更速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"變更速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"變更速度\"\n          }\n        }\n      }\n    },\n    \"Check for updates automatically\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soek outomaties vir opdaterings\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التحقق من التحديثات تلقائيًا\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatski provjeravaj nadogradnje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Comprova les actualitzacions automàticament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaticky kontrolovat aktualizace\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Søg automatisk efter opdateringer\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatisch nach Aktualisierungen suchen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αυτόματος έλεγχος για ενημερώσεις\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar actualizaciones automáticamente\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tarkista päivitykset automaattisesti\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechercher des mises à jour automatiquement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בדוק עדכונים באופן אוטומטי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Frissítések automatikus keresése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Periksa pembaruan secara otomatis\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verifica automaticamente gli aggiornamenti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新を自動的に確認する\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"자동으로 업데이트 확인\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက် update များကို စစ်ဆေးပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se etter oppdateringer automatisk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatisch controleren op updates\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sprawdzaj aktualizacje automatyczne\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificar atualizações automaticamente\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificar por atualizações automaticamente\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificați automat dacă există actualizări\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автоматически проверять наличие обновлений\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automaticky kontrolovať aktualizácie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatski proveri ažuriranja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sök efter uppdateringar automatiskt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncellemeleri otomatik kontrol et\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автоматично перевіряти наявність оновлень\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiểm tra cập nhật tự động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自动检查更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自動檢查更新\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用自動更新\"\n          }\n        }\n      }\n    },\n    \"Check for Updates…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soek vir opdaterings…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"جاري التحقق من وجود تحديثات…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Provjeri nadogradnje…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Comprova si hi ha actualitzacions…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zkontrolovat aktualizace…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Søg efter Opdateringer…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach Updates suchen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Έλεγχος για ενημερώσεις…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar actualizaciones…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tarkista päivitykset…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechercher des mises à jour…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בודק אחר עדכונים…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Frissítések keresése…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Periksa Pembaruan…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Controlla aggiornamenti…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アップデートを確認\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트 확인…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update များစစ်ရန်…\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se etter oppdateringer…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Controleer op Updates…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sprawdź aktualizacje…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificar atualizações…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar Atualizações…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificați dacă există actualizări…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Проверить наличие обновлений…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyhľadať aktualizácie…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Proveri ažuriranja…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sök efter uppdateringar…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncellemeleri kontrol et…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перевіряти наявність оновлень…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiểm tra cập nhật…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"检查更新…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"檢查更新…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"檢查更新…\"\n          }\n        }\n      }\n    },\n    \"Choose a feel preset.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kies 'n voorgevoel-voorinstelling.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اختر إعدادًا مسبقًا للشعور.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odaberite unaprijed postavljeni osjećaj.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tria un predefinit de sensació.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyberte předvolbu pocitu.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vælg en forudindstilling for følelse.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wählen Sie eine Voreinstellung für das Scroll-Gefühl.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιλέξτε μια προεπιλογή αίσθησης.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elige un ajuste preestablecido de sensación.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valitse tuntumaesiasetus.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Choisir un préréglage de sensation.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בחר הגדרה מוגדרת מראש לתחושה.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Válasszon egy előre beállított érzetet.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pilih preset nuansa.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scegli un'impostazione predefinita per la sensazione.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感触プリセットを選択します。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"느낌 사전 설정을 선택하세요.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ခံစားမှုကြိုတင်သတ်မှတ်ချက်ကို ရွေးချယ်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velg en forhåndsinnstilling for følelse.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kies een vooringestelde scrollgevoeligheid.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wybierz ustawienie wstępne czułości.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Escolha uma predefinição de sensação.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Escolha uma predefinição de sensação.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alegeți o presetare de senzație.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выберите предустановку отклика.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyberte predvoľbu pocitu.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izaberi unapred podešeni osećaj.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Välj en förinställning för känsla.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bir his ayarı seçin.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Виберіть попередньо встановлене значення чутливості.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chọn một cài đặt trước về cảm giác.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"选择一种感觉预设。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選擇一個觸感預設。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選擇預設的捲動感。\"\n          }\n        }\n      }\n    },\n    \"Choose a mouse button trigger. Left click without modifier keys is not allowed.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kies 'n muisknoppie-sneller. Linkskliek sonder wysigingsleutels word nie toegelaat nie.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اختر مشغل زر الماوس. لا يُسمح بالنقر الأيسر بدون مفاتيح تعديل.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odaberite okidač tipke miša. Lijevi klik bez modifikatorskih tipki nije dozvoljen.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tria un disparador de botó del ratolí. No es permet fer clic esquerre sense tecles modificadores.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyberte spoušť tlačítka myši. Kliknutí levým tlačítkem bez modifikačních kláves není povoleno.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vælg en museknapudløser. Venstreklik uden genvejstaster er ikke tilladt.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wählen Sie eine Maustastenauslösung. Ein Linksklick ohne Modifikatortasten ist nicht erlaubt.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιλέξτε ένα έναυσμα κουμπιού ποντικιού. Το αριστερό κλικ χωρίς πλήκτρα τροποποίησης δεν επιτρέπεται.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elige un disparador de botón del ratón. No se permite el clic izquierdo sin teclas modificadoras.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valitse hiiren painikkeen laukaisin. Vasemmanpuoleinen napsautus ilman muokkausnäppäimiä ei ole sallittua.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Choisir un déclencheur de bouton de souris. Le clic gauche sans touches modificatrices n’est pas autorisé.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בחר טריגר עבור לחצן עכבר. לחיצה שמאלית ללא מקשי שינוי אינה מותרת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Válasszon egy egérgomb-eseményindítót. A módosítóbillentyűk nélküli bal kattintás nem megengedett.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pilih pemicu tombol mouse. Klik kiri tanpa tombol pengubah tidak diperbolehkan.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scegli un pulsante del mouse come trigger. Non è consentito il clic sinistro senza tasti modificatori.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"マウスボタンのトリガーを選択します。修飾キーなしの左クリックは許可されていません。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"마우스 버튼 트리거를 선택하세요. 수정자 키 없이 왼쪽 클릭은 허용되지 않습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မောက်ခလုတ်ကိုနှိုးဆွတ်ရန် ရွေးချယ်ပါ။ modifier keys မပါဘဲ ဘယ်ဘက်ကလစ်ကို ခွင့်မပြုပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velg en museknapputløser. Venstreklikk uten modifikasjonstaster er ikke tillatt.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kies een muisknop als trigger. Linkerklik zonder modificatietoetsen is niet toegestaan.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wybierz przycisk myszy jako wyzwalacz. Kliknięcie lewym przyciskiem bez klawiszy modyfikujących jest niedozwolone.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Escolha um gatilho de botão do mouse. Clique esquerdo sem teclas modificadoras não é permitido.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Escolha um gatilho de botão do mouse. Clique com o botão esquerdo sem teclas modificadoras não é permitido.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alegeți un declanșator de buton de mouse. Nu este permis clic stânga fără taste modificatoare.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выберите триггер кнопки мыши. Левый клик без модификаторов запрещен.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyberte spúšťač tlačidla myši. Kliknutie ľavým tlačidlom bez modifikačných klávesov nie je povolené.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izaberite okidač dugmeta miša. Levi klik bez modifikatora nije dozvoljen.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Välj en musknappstrigger. Vänsterklick utan modifieringstangenter är inte tillåtet.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bir fare düğmesi tetikleyicisi seçin. Değiştirici tuşlar olmadan sol tıklamaya izin verilmez.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Виберіть тригер кнопки миші. Натискання лівої кнопки без допоміжних клавіш заборонено.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chọn một trình kích hoạt nút chuột. Không cho phép nhấp chuột trái mà không có phím sửa đổi.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"选择一个鼠标按钮触发器。不允许使用不带修饰键的左键单击。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選擇滑鼠按鈕觸發條件。不允許使用不含修飾鍵的左鍵點按。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選擇滑鼠按鈕觸發器。不允許在沒有組合鍵的情況下按一下左鍵。\"\n          }\n        }\n      }\n    },\n    \"Click and release to keep autoscroll active, or hold and drag to scroll only until you let go.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik en laat los om outomatiese blaai aktief te hou, of hou vas en sleep om slegs te blaai totdat jy loslaat.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انقر وحرر للحفاظ على التمرير التلقائي نشطًا، أو اضغط واسحب للتمرير فقط حتى تفلت.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite i otpustite da biste zadržali automatsko pomicanje aktivnim, ili držite i prevlačite da biste pomicali samo dok ne otpustite.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fes clic i deixa anar per mantenir el desplaçament automàtic actiu, o mantén premut i arrossega per desplaçar-te només fins que deixis anar.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutím a uvolněním ponecháte automatické rolování aktivní, nebo podržením a přetažením budete rolovat jen do uvolnění.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik og slip for at holde autoscroll aktiv, eller hold og træk for kun at rulle, indtil du slipper.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicken und loslassen, um das automatische Scrollen beizubehalten, oder halten und ziehen, um nur zu scrollen, bis Sie loslassen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κάντε κλικ και αφήστε για να παραμείνει ενεργή η αυτόματη κύλιση, ή κρατήστε πατημένο και σύρετε για να κάνετε κύλιση μόνο μέχρι να αφήσετε.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Haz clic y suelta para mantener activo el desplazamiento automático, o mantén presionado y arrastra para desplazarte solo hasta que sueltes.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Napsauta ja vapauta pitääksesi automaattisen vierityksen aktiivisena, tai pidä ja vedä vierittääksesi vain siihen asti, kunnes vapautat.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cliquez et relâchez pour maintenir le défilement automatique actif, ou maintenez et faites glisser pour faire défiler uniquement jusqu’à ce que vous relâchiez.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחץ ושחרר כדי להשאיר את הגלילה האוטומטית פעילה, או החזק וגרור כדי לגלול רק עד שתשחרר.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kattintson és engedje fel az automatikus görgetés aktívan tartásához, vagy tartsa lenyomva és húzza az egérrel a görgetéshez, amíg el nem engedi.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik dan lepas untuk menjaga gulir otomatis tetap aktif, atau tahan dan seret untuk menggulir hanya sampai Anda melepasnya.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fai clic e rilascia per mantenere attivo lo scorrimento automatico, oppure tieni premuto e trascina per scorrere solo finché non rilasci.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"クリックして離すとオートスクロールがアクティブになり、押したままドラッグすると離すまでスクロールします。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"클릭 후 놓으면 자동 스크롤이 유지되고, 누른 상태로 드래그하면 놓을 때까지만 스크롤됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက် scroll ကို အသက်ဝင်စေရန် ကလစ်နှိပ်ပြီး လွှတ်ပါ၊ သို့မဟုတ် ဖိကိုင်ပြီး လွှတ်သည်အထိသာ scroll လုပ်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klikk og slipp for å holde autoskroll aktiv, eller hold inne og dra for å rulle bare til du slipper.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik en laat los om automatisch scrollen actief te houden, of houd ingedrukt en sleep om te scrollen totdat je loslaat.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknij i puść, aby przewijanie automatyczne pozostało aktywne, lub przytrzymaj i przeciągnij, aby przewijać tylko do momentu zwolnienia przycisku.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique e solte para manter a rolagem automática ativa, ou segure e arraste para rolar apenas até soltar.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique e solte para manter a rolagem automática ativa, ou segure e arraste para rolar apenas até soltar.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faceți clic și eliberați pentru a menține activ derularea automată, sau țineți apăsat și trageți pentru a derula doar până când eliberați.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нажмите и отпустите, чтобы включить автопрокрутку, или нажмите и удерживайте, чтобы прокручивать только во время удержания.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutím a uvoľnením ponechajte automatické rolovanie aktívne, alebo podržte a potiahnite, aby ste rolovali iba dovtedy, kým nepustíte.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite i otpustite da biste zadržali automatsko pomeranje aktivnim, ili držite i prevucite da biste pomerili samo dok ne otpustite.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicka och släpp för att hålla autoscroll aktiv, eller håll och dra för att bara rulla tills du släpper.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otomatik kaydırmayı etkin tutmak için tıklayıp bırakın veya yalnızca bırakana kadar kaydırmak için basılı tutup sürükleyin.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клацніть і відпустіть, щоб автопрокручування залишалося активним, або натисніть і перетягніть, щоб прокручувати лише до відпускання.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhấp và thả để giữ cho tính năng tự động cuộn hoạt động, hoặc giữ và kéo để cuộn cho đến khi bạn thả tay.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"单击并释放以保持自动滚动处于活动状态，或按住并拖动以仅在松开前滚动。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"點按並放開以保持自動捲動作用中，或按住並拖移以僅在放開前捲動。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按一下並放開以保持自動捲動作用中，或按住並拖曳以僅在放開前捲動。\"\n          }\n        }\n      }\n    },\n    \"Click once to toggle\" : {\n      \"comment\" : \"Autoscroll mode label. One click turns the mode on or off.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik een keer om te wissel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انقر مرة واحدة للتبديل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite jednom za prebacivanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fes clic una vegada per alternar\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jedním kliknutím přepnete\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik én gang for at skifte\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einmal klicken zum Umschalten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κάντε κλικ μία φορά για εναλλαγή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Haz clic una vez para alternar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Napsauta kerran vaihtaaksesi\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic unique pour activer/désactiver\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחץ פעם אחת כדי להפעיל/לכבות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kattintson egyszer a váltáshoz\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik sekali untuk mengalihkan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fai clic una volta per attivare/disattivare\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"一度クリックして切り替え\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"한 번 클릭하여 전환\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တစ်ကြိမ်ကလစ်နှိပ်၍ ဖွင့်/ပိတ်လုပ်ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klikk én gang for å veksle\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eén keer klikken om te wisselen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknij raz, aby przełączyć\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique uma vez para alternar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique uma vez para alternar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faceți clic o dată pentru a comuta\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Однократный клик для переключения\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutím prepnete\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite jednom za prebacivanje\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicka en gång för att växla\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Açıp kapatmak için bir kez tıklayın\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клацніть один раз, щоб перемкнути\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhấp một lần để chuyển đổi\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"单击一次以切换\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"點按一次以切換\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按一下以切換\"\n          }\n        }\n      }\n    },\n    \"Click the trigger once to enter autoscroll, move in any direction to scroll, then click again to exit.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik die sneller een keer om outomatiese blaai te betree, beweeg in enige rigting om te blaai, klik dan weer om uit te gaan.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انقر على المشغل مرة واحدة للدخول في التمرير التلقائي، وحرك في أي اتجاه للتمرير، ثم انقر مرة أخرى للخروج.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite okidač jednom za ulazak u automatsko pomicanje, pomičite se u bilo kojem smjeru za pomicanje, zatim kliknite ponovo za izlaz.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fes clic al disparador una vegada per entrar al desplaçament automàtic, mou-te en qualsevol direcció per desplaçar-te i, a continuació, fes clic de nou per sortir.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jedním kliknutím na spoušť vstoupíte do automatického rolování, libovolným směrem se posunete a dalším kliknutím rolování ukončíte.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik på udløseren én gang for at gå ind i autoscroll, bevæg dig i enhver retning for at rulle, og klik derefter igen for at afslutte.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicken Sie einmal auf die Auslösetaste, um das automatische Scrollen zu starten, bewegen Sie sich in eine beliebige Richtung, um zu scrollen, und klicken Sie dann erneut, um es zu beenden.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κάντε κλικ στο έναυσμα μία φορά για να εισέλθετε στην αυτόματη κύλιση, μετακινηθείτε προς οποιαδήποτε κατεύθυνση για κύλιση και, στη συνέχεια, κάντε ξανά κλικ για έξοδο.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Haz clic en el disparador una vez para entrar en el desplazamiento automático, muévete en cualquier dirección para desplazarte y luego haz clic de nuevo para salir.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Napsauta laukaisinta kerran siirtyäksesi automaattiseen vieritykseen, liikuta mihin tahansa suuntaan vierittääksesi ja napsauta sitten uudelleen poistuaksesi.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cliquez une fois sur le déclencheur pour activer le défilement automatique, déplacez-vous dans n’importe quelle direction pour faire défiler, puis cliquez à nouveau pour quitter.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחץ על הטריגר פעם אחת כדי להיכנס לגלילה אוטומטית, הזז לכל כיוון כדי לגלול, ואז לחץ שוב כדי לצאת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kattintson az eseményindítóra egyszer az automatikus görgetés elindításához, mozgassa bármely irányba a görgetéshez, majd kattintson újra a kilépéshez.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik pemicu sekali untuk masuk ke gulir otomatis, gerakkan ke arah mana pun untuk menggulir, lalu klik lagi untuk keluar.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fai clic sul trigger una volta per attivare lo scorrimento automatico, muoviti in qualsiasi direzione per scorrere, quindi fai clic di nuovo per uscire.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"トリガーを一度クリックしてオートスクロールを開始し、任意の方向に移動してスクロールしてから、もう一度クリックして終了します。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"트리거를 한 번 클릭하여 자동 스크롤 모드로 들어가고, 원하는 방향으로 이동하여 스크롤한 다음 다시 클릭하여 종료합니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက် scroll ဝင်ရန် နှိုးဆွတ်ကို တစ်ကြိမ်ကလစ်နှိပ်ပါ၊ scroll လုပ်ရန် မည်သည့် ဦးတည်ရာသို့မဆို ရွှေ့ပါ၊ ထို့နောက် ထွက်ရန် ထပ်မံကလစ်နှိပ်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klikk utløseren én gang for å aktivere autoskroll, beveg i hvilken som helst retning for å rulle, klikk deretter igjen for å avslutte.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik één keer op de trigger om automatisch scrollen te starten, beweeg in elke richting om te scrollen en klik nogmaals om te stoppen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknij raz wyzwalacz, aby wejść w tryb przewijania automatycznego, przesuń w dowolnym kierunku, aby przewijać, a następnie kliknij ponownie, aby wyjść.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique no gatilho uma vez para entrar na rolagem automática, mova-se em qualquer direção para rolar e clique novamente para sair.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique no gatilho uma vez para entrar na rolagem automática, mova-se em qualquer direção para rolar e clique novamente para sair.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faceți clic o dată pe declanșator pentru a intra în modul de derulare automată, mișcați în orice direcție pentru a derula, apoi faceți clic din nou pentru a ieși.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нажмите триггер один раз, чтобы начать автопрокрутку, перемещайте курсор в любом направлении для прокрутки, затем нажмите еще раз, чтобы выйти.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutím na spúšťač raz vstúpite do automatického rolovania, pohybom ľubovoľným smerom rolujete a potom opätovným kliknutím ukončíte.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite jednom na okidač da biste ušli u automatsko pomeranje, pomerajte se u bilo kom pravcu da biste se pomerali, a zatim kliknite ponovo da biste izašli.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicka på utlösaren en gång för att aktivera autoscroll, rör dig i valfri riktning för att rulla, klicka sedan igen för att avsluta.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otomatik kaydırmaya girmek için tetikleyiciye bir kez tıklayın, kaydırmak için herhangi bir yöne hareket edin, ardından çıkmak için tekrar tıklayın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клацніть тригер один раз, щоб увійти в режим автопрокручування, рухайтеся в будь-якому напрямку для прокручування, а потім клацніть ще раз, щоб вийти.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhấp vào trình kích hoạt một lần để vào chế độ tự động cuộn, di chuyển theo bất kỳ hướng nào để cuộn, sau đó nhấp lại để thoát.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"单击触发器一次以进入自动滚动，向任意方向移动以滚动，然后再次单击以退出。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"點按觸發條件一次以進入自動捲動，朝任一方向移動以捲動，然後再點按一次以退出。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按一下觸發器進入自動捲動，朝任一方向移動以捲動，然後再按一下以退出。\"\n          }\n        }\n      }\n    },\n    \"Click to record\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik om op te neem\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انقر للتسجيل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klikni za snimanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fes clic per gravar\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutím nahrávej\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik for at optage\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicke zum Aufzeichnen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πατήστε για εγγραφή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic para grabar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Napsauta tallentaaksesi\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cliquez pour enregistrer\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחץ להקליט\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kattintson a rögzítéshez\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik untuk merekam\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fai clic per registrare\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"クリックして記録\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"클릭하여 입력\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မှတ်တမ်းတင်ရန် နှိပ်ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klikk for å registrere\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik om op te nemen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknij, aby zarejestrować\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique para gravar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique para gravar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faceți clic pentru a înregistra\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нажмите для записи\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknutím nahráte\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kliknite za snimanje\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klicka för att spela in\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydetmek için tıklayın\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клацніть, щоб записувати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhấn để ghi\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"点击录制\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"點擊錄製\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"點擊錄製\"\n          }\n        }\n      }\n    },\n    \"Config\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إعدادات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguracija\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Config.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurační soubory\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διαμόρφωση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuración\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Asetukset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדרות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguráció\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurazione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဆက်တင်များ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasjon\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguracja\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuração\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuração\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Конфигурация\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurácia\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Конфигурација\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfig\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayarlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Налаштування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cấu hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        }\n      }\n    },\n    \"Configuration Reloaded\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasie Herlaai\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تم إعادة تحميل الإعدادات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguracija osvježena\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuració recarregada\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurace znovu načtena\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration genindlæst\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration neu geladen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επαναφόρτωση Ρυθμίσεων\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuración cargada\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määritykset ladattu uudelleen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration rechargée\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התצורה נטענה מחדש\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguráció újratöltve\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasi Dimuat Ulang\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurazione ricaricata\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定を再読み込みしました\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 새로고침 완료됨\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration ပြန်တင်ပြီးပါပြီ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasjon lastet inn på nytt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie opnieuw geladen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguracja przeładowana\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuração Recarregada\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuração Recarregada\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurare reîncărcată\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Конфигурация перезагружена\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurácia obnovená\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguracija ponovo učitana\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurationen laddades om\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırma Yeniden Yüklendi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Конфігурацію перезавантажено\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đã tải lại Cấu hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"配置已重新加载\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定已重新載入\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已重新載入設定\"\n          }\n        }\n      }\n    },\n    \"Configure for\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stel op virr\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكوين لـ\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguriši za\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configura per a\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurovat pro\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indstil for\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguriere für\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ρύθμιση για\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuración para\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määritä kohteelle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurer pour\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדר עבור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurálás ehhez\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasikan untuk\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configura per\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定：\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"에 대해 설정…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြင်ဆင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurer for\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configureer voor\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skonfiguruj dla\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurar para\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurar para\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurare pentru\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Настроить для\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurovať pre\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Конфигуриши за\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurera för\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Налаштувати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cấu hình cho\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"应用于\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"應用於\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"應用於\"\n          }\n        }\n      }\n    },\n    \"Configure for %@…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stel op virr %@…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكوين لـ %@…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguriši za %@…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configura per a %@…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurovat pro %@…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indstil for %@…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguriere für %@…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ρύθμιση παραμέτρων για το %@…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurar para %@…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määritä kohteelle %@…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurer pour %@…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדרות עבור %@…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurálás ehhez: %@…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasikan untuk %@…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configura per %@…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@の設定…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@에 대해 설정…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@… အတွက် စီစဉ်သတ်မှတ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurer for %@…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configureer voor %@…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguruj dla %@…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurar para %@…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurar para %@…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurare pentru %@…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Настроить для %@…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurovať pre %@…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Конфигуриши за %@…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurera för %@…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ için ayarla…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Налаштування для %@…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cấu hình cho %@…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"为 %@ 配置…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"為 %@ 配置…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"為 %@ 配置…\"\n          }\n        }\n      }\n    },\n    \"Configured\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gekonfigureer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تم التكوين\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurisano\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurováno\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indstillet\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguriert\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διαμορφωμένες\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määritetty\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuré\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הוגדר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurálva\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terkonfigurasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定済みのアプリ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정됨\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြင်ဆင်ပြီး\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurert\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geconfigureerd\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skonfigurowane\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Настроены\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nakonfigurované\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurisano\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurerad\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırılmış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Налаштовані\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đã cấu hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已配置\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已配置\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已配置\"\n          }\n        }\n      }\n    },\n    \"Convert pointer movement to scroll events\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skakel wyserbeweging om na blaai-gebeurtenisse\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تحويل حركة المؤشر إلى أحداث تمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pretvori pokrete miša u događaje skrolanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converteix el moviment del punter en esdeveniments de desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Převést pohyb ukazatele na události rolování\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konverter markørbevægelse til rullehændelser\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeigerbewegung in Scrollereignisse umwandeln\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μετατροπή κίνησης δείκτη σε συμβάντα κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Convierte el movimiento del puntero en eventos de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muunna osoittimen liike vieritystapahtumiksi\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Convertir les mouvements du pointeur en événements de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"המר תנועות מצביע לאירועי גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutatómozgatás görgetési eseményekké alakítása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubah gerakan penunjuk menjadi peristiwa gulir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converti il movimento del puntatore in eventi di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ポインターの動きをスクロールイベントに変換\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"포인터 움직임을 스크롤 이벤트로 변환\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pointer ရွေ့လျားမှုကို scroll ဖြစ်ရပ်များအဖြစ် ပြောင်းလဲပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konverter pekerbevegelse til rullingshendelser\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verplaatsing van de aanwijzer omzetten in scrollgebeurtenissen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konwertuj ruch wskaźnika na zdarzenia przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converter movimento do ponteiro em eventos de rolagem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converter movimento do ponteiro em eventos de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Convertiți mișcarea indicatorului în evenimente de derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Преобразовать движение указателя в события прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prevod pohybu ukazovateľa na udalosti rolovania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pretvori pomeranje pokazivača u događaje pomeranja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konvertera pekarrörelser till rullningshändelser\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşaretçi hareketini kaydırma olaylarına dönüştür\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перетворювати рух вказівника на події прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuyển đổi chuyển động con trỏ thành sự kiện cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"将指针移动转换为滚动事件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將指標移動轉換為捲動事件\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將指標移動轉換為捲動事件\"\n          }\n        }\n      }\n    },\n    \"Convert the back and forward side buttons to swiping gestures to allow universal back and forward functionality.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skakel die agterste en voorste syknoppies om na veebewegings om universele agter- en vooruit-funksionaliteit toe te laat.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تحويل الأزرار الجانبية للخلف وللأمام إلى إيماءات سحب للسماح بوظيفة عالمية للخلف وللأمام.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pretvorite bočne tipke za kretanje naprijed i nazad u geste prevlačenja kako biste omogućili univerzalnu funkcionalnost za kretanje naprijed i nazad.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converteix els botons laterals d'avanç i retrocés en gestos de lliscar per permetre una funcionalitat universal d'avanç i retrocés.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Převádí stisk bočních tlačítek myši pro pohyb zpět a dopředu na gesta přejetí prstem (swipe) a tím umožňuje využití tlačítek pro navigaci\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konverter tilbage og frem sideknapperne til strygebevægelser for at tillade universel tilbage og frem funktionalitet.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konvertiert die Vor- und Zurück-Seitentasten in die jeweiligen Wischgesten, um eine universelle Vor- und Zurück-Funktion zu ermöglichen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μετατρέψτε τα πίσω και προς τα εμπρός πλευρικά κουμπιά σε χειρονομίες για την καθολική ενεργοποίηση της λειτουργίας πίσω και εμπρός.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Convierte los botones laterales atrás y adelante en gestos de deslizamiento para permitir una funcionalidad universal hacia atrás y hacia delante.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muunna sivun edestakaisin-painikkeet pyyhkäisytoiminnoiksi, jotta voit käyttää yleistä edestakaisin-toimintoa.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Convertir les boutons latéraux arrière et avant en swipant pour permettre la fonctionnalité universelle de retour et d'avant.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"המרת כפתורי הצד האחורי והקדמי לתנועת החלקה כדי לאפשר פונקציות אחור וקדימה גלובליות.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alakítsa át a bal és jobb oldali gombokat ellopási gesztusokká az univerzális előre és hátra funkció engedélyezéséhez.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubah tombol samping maju dan mundur menjadi gestur geser untuk mengaktifkan fungsi maju dan mundur universal.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converti i pulsanti laterali avanti e indietro in gesti di scorrimento per consentire funzionalità di avanti e indietro universali.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"戻る・進むボタンをスワイプジェスチャーに変換し、システム全般における戻る・進む機能を行えるようにします。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"뒤로 및 앞으로 가기 측면 버튼을 스와이프 제스처로 변환하여 앱 호환성을 향상시킵니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse ရှိဘေးခလုတ်များအား Windows system အတိုင်း back and forward ထားရန်။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konverter tilbake- og fremover-sideknappene til sveipegester for å aktivere universell tilbake og fremover-funksjonalitet.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verander de functie van de heen- en terugknoppen naar veeggebaren om de universele heen- en terug functie in te schakelen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zamienia działanie przycisków bocznych myszy na gesty przesuwania, tak aby umożliwić uniwersalne przechodzenie wstecz i do przodu.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converte os botões laterais de avanço e retrocesso em gestos de deslizamento para permitir a funcionalidade de avanço e retrocesso universal.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Converte os botões laterais de retorno e avanço para gestos do trackpad para habilitar a funcionalidade de retorno e avanço universal.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Convertește butoanele din spate și din față lateral la gesturi de glisare pentru a permite funcționalitatea universală înapoi și înainte.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Преобразует боковые кнопки «назад» и «вперед» в жесты смахивания, чтобы сделать их работоспособными во всех приложениях.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Premeňte bočné tlačidlá dozadu a dopredu na gestá posúvania, aby ste umožnili univerzálne funkcie dozadu a dopredu.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pretvori bočna dugmad za napred i nazad u pokrete prevlačenja da bi se omogućila univerzalna funkcionalnost napred i nazad.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konvertera sidoknapparna framåt och bakåt till svepgester för universell framåt- och bakåtfunktion.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Evrensel ileri ve geri işlevine izin vermek için ileri ve geri yan düğmelerini kaydırma hareketlerine dönüştürün.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перетворити бічні кнопки «Назад» і «Уперед» на жести проведення, щоб забезпечити універсальну функцію «Назад» і «Уперед».\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuyển đổi các nút quay lại và chuyển tiếp sang cử chỉ vuốt để cho phép chức năng quay lại và chuyển tiếp phổ biến.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"将后退、前进侧键转换为滑动手势，以全局启用后退、前进支持。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將後退、前進側鍵轉換為滑動手勢，以啟用全局的後退、前進功能。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"將後退、前進側鍵轉換為滑動手勢，以全局啟用後退、前進支持。\"\n          }\n        }\n      }\n    },\n    \"Copy settings from vertical\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopieer instellings van vertikaal\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"نسخ الإعدادات من الوضع الرأسي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopiraj postavke od vertikalnog\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copia la configuració de vertical\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zkopírovat nastavení z vertikály\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopiér indstillinger fra vertikal\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einstellungen von Vertikal übernehmen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αντιγραφή ρυθμίσεων από κάθετη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copiar ajustes de la vertical\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopioi asetukset pystysuunnasta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copier les paramètres de la catégorie \\\"Vertical\\\"\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"העתקת הגדרות מ'אנכי'\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beállítások másolása függőlegesből\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Salin pengaturan dari vertikal\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copia le impostazioni dalla verticale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"縦方向と同じ設定を適用\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"수직 방향 설정 복사\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical မှ settings များကို ကူးယူပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopier innstillinger fra vertikal\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instellingen overnemen van verticaal\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skopiuj ustawienia z pionowego\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copiar definições de vertical\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copiar definições verticais\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Copiați setările de la verticală\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скопировать настройки из вертикальной\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopírovať nastavenia z vertikálneho\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopiraj postavke sa vertikalnih\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kopiera inställningar från vertikal\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayarları \\\"Dikey\\\" kategorisinden kopyala\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Копіювати налаштування з вертикальних\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sao chép cài đặt\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"从纵向复制设置\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"從縱向拷貝設定\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"從縱向拷貝設定\"\n          }\n        }\n      }\n    },\n    \"Create\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skep\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إنشاء\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kreiraj\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Crea\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vytvořit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opret\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erstellen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δημιουργία\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Crear\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Luo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Créer\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"צור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Létrehozás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buat\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Crea\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"作成\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"생성\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖန်တီးရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opprett\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanmaken\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utwórz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Criar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Criar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Creează\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Создать\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vytvoriť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kreiraj\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skapa\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oluştur\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Створити\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tạo\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"创建\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"建立\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"建立\"\n          }\n        }\n      }\n    },\n    \"Cubic ease-in-out with a weightier middle section.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubiese geleidelike begin en einde met 'n swaarder middelgedeelte.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع وتباطؤ تدريجي تكعيبي مع قسم أوسط أثقل.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubični postepeni početak i završetak sa snažnijim srednjim dijelom.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada i sortida suaus cúbiques amb una secció central més densa.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubický pozvolný náběh a doznění s výraznější střední částí.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk blød start og afslutning med en tungere midtersektion.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubischer sanfter Start und sanftes Ende mit kräftigerem Mittelteil.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κυβική ομαλή έναρξη και λήξη με πιο βαρύ μεσαίο τμήμα.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada y salida suaves cúbicas con una sección media más marcada.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuutiollinen pehmeä alku ja loppu, jossa keskiosa tuntuu painavammalta.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée et sortie douces cubiques avec une section médiane plus marquée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה וסיום הדרגתיים קובייתיים עם חלק אמצעי כבד יותר.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Köbös lágy indulás és lecsengés, súlyosabb középső szakasszal.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out kubik dengan bagian tengah yang lebih berbobot.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out cubico con una sezione centrale più corposa.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中盤に重みを持たせた、キュービックのイーズインアウトです。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"중간 구간에 더 무게감이 있는 큐빅 이즈 인 아웃입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ်ပိုင်း ပိုတည်ငြိမ်လေးနက်သော cubic ease-in-out ဖြစ်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk myk start og avslutning med en tyngre midtseksjon.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubische geleidelijke start en uitloop met een zwaarder middendeel.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sześcienne łagodne narastanie i wyhamowanie z cięższym środkiem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out cúbico com uma secção intermédia mais pesada.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out cúbico com uma seção central mais encorpada.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out cubic, cu o secțiune mediană mai grea.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кубический ease-in-out с более плотной серединой.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubické ease-in-out s výraznejšou strednou časťou.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кубни ease-in-out са тежишнијим средишњим делом.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk ease-in-out med en tyngre mittsektion.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Orta bölümü daha ağır hissedilen kübik ease-in-out.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кубічний ease-in-out із вагомішою серединою.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out bậc ba với phần giữa đầm hơn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次缓入缓出，中段更有分量。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次緩入緩出，中段更有分量。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次緩入緩出，中段更有分量。\"\n          }\n        }\n      }\n    },\n    \"Custom\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pasgemaak\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مخصص\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prilagođeno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personalitzat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vlastní\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brugerdefineret\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Benutzerdefiniert\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Προσαρμοσμένο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personalizado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mukautettu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personnalisé\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מותאם אישית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egyéni\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kustom\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personalizzato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"カスタム\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사용자 설정\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"စိတ်ကြိုက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilpasset\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aangepast\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Własne\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personalizado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personalizado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Personalizat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пользовательский\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vlastné\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прилагођено\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anpassad\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Özel\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Власний\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tùy chỉnh\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自定义\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自訂\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"自訂\"\n          }\n        }\n      }\n    },\n    \"Daily\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daagliks\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يومي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dnevno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diari\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Denně\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dagligt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Täglich\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ημερησίως\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cada día\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Päivittäin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tous les jours\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"יומי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naponta\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Harian\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogni giorno\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"毎日\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"매일\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နေ့တိုင်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daglig\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dagelijks\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codziennie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diariamente\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diariamente\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zilnic\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ежедневно\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Denne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dnevno\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dagligen\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Günlük\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Щоденно\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hằng ngày\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每天\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每天\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每日\"\n          }\n        }\n      }\n    },\n    \"Debounce button clicks\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Debounce knoppie kliks\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تأخير نقرات الأزرار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klikovi na dugme za ublažavanje odskoka\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Retarda els clics dels botons\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorovat odrazy tlačítka\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Undgå gentagelse af klik\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entprellen von Mausklicks\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Παράβλεψη γρήγορων κλικ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Evitar pulsaciones involuntarias\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vaimenna painikkeen napsautukset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anti-rebond des clics de la souris\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התעלם מלחיצות כפתור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gombkattintások késleltetése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Debounce klik tombol\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Antirimbalzo dei clic del pulsante\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"チャタリング防止\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버튼 클릭 간격\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ခလုတ်နှိပ်ချက်များကို ကန့်သတ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Filtrer knappedobbeltklikk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onbedoelde dubbelklik negeren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odfiltruj kliknięcia przycisków\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Limitar cliques rápidos dos botões\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Debounce de cliques do botão\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Amânați apăsările de butoane\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пропускать нажатие кнопок\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Čas odozvy kliknutia na tlačidlá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odloži klikove na dugmad\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avvisa knappklick\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buton arkını engelle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пропускати клацання кнопок\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sửa lỗi nháy chuột nhiều lần\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按钮点击去抖动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按鈕點擊去抖動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按鈕點擊去抖動\"\n          }\n        }\n      }\n    },\n    \"Decrease display brightness\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verminder skermhelderheid\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تقليل سطوع الشاشة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smanji osvjetljenje ekrana\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disminueix la brillantor de la pantalla\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snížit jas displeje\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sænk lysstyrke\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bildschirmhelligkeit verringern\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μείωση φωτεινότητας οθόνης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disminuir brillo de pantalla\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pienennä näytön kirkkautta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baisser la luminosité d'affichage\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הנמך בהירות תצוגה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Képernyő fényerejének csökkentése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurangi kecerahan layar\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Riduci la luminosità dello schermo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ディスプレイの明るさを下げる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"화면 밝기 낮추기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Screen အလင်း လျော့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reduser skjermlysstyrke\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verlaag schermhelderheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmniejsz jasność wyświetlacza\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reduzir brilho do monitor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diminuir brilho da tela\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scădere luminozitate ecran\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Уменьшить яркость экрана\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zníženie jasu displeja\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smanji osvetljenost ekrana\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Minska skärmens ljusstyrka\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekran parlaklığını azalt\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зменшити яскравість дисплея\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giảm độ sáng màn hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低显示器亮度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低顯示器亮度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低顯示器亮度\"\n          }\n        }\n      }\n    },\n    \"Decrease keyboard brightness\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verminder sleutelbordhelderheid\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تقليل سطوع لوحة المفاتيح\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smanji osvjetljenje tastature\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disminueix la brillantor del teclat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snížit jas klávesnice\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reducer tastaturets lysstyrke\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastaturhelligkeit verringern\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μείωση φωτεινότητας πληκτρολογίου\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reducir el brillo del teclado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pienennä näppäimistön kirkkautta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baisser la luminosité d'affichage\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הנמך בהירות מקלדת\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Billentyűzet fényerejének csökkentése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurangi kecerahan keyboard\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diminuisci la luminosità della tastiera\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ディスプレイの明るさを下げる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"키보드 밝기 낮추기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ကီးဘုတ် အလင်း လျော့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reduser tastaturlysstyrke\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Helderheid van toetsenbord verlagen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmniejsz jasność klawiatury\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diminuir brilho do teclado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diminuir brilho do teclado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scădere luminozitate tastatură\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Уменьшить яркость клавиатуры\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zníženie jasu klávesnice\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smanji osvetljenost tastature\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Minska tangentbordets ljusstyrka\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klavye parlaklığını azalt\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зменшити яскравість клавіатури\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giảm độ sáng bàn phím\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低键盘亮度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低鍵盤亮度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低鍵盤亮度\"\n          }\n        }\n      }\n    },\n    \"Decrease volume\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verminder volume\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خفض مستوى الصوت\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smanji glasnoću zvuka\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disminueix el volum\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snížit hlasitost\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sænk lydstyrke\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lautstärke verringern\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μείωση έντασης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disminuir volumen\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pienennä äänenvoimakkuutta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baisser le volume\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלש את עוצמת הקול\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hangerő csökkentése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurangi volume\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diminuisci il volume\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"音量を下げる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"음량 낮추기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အသံတိုးရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reduser volum\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verlaag volume\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przycisz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reduzir volume\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diminuir volume\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scădere volum\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Уменьшить громкость\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Znížiť hlasitosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smanji jačinu zvuka\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sänk volym\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ses seviyesini azalt\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зменшити гучність\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giảm âm lượng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低音量\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低音量\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"降低音量\"\n          }\n        }\n      }\n    },\n    \"Default action\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verstek aksie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الإجراء الافتراضي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zadana funkcija\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acció per defecte\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Výchozí akce\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standardhandling\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standardaktion\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Προεπιλεγμένη ενέργεια\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acción predeterminada\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oletustoiminto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Action par défaut\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"פעולת ברירת מחדל\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alapértelmezett művelet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tindakan bawaan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Azione predefinita\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"デフォルトの動作\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기본 동작\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နဂိုမူလ လုပ်ဆောင်ချက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standardhandling\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standaard actie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Domyślna akcja\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ação predefinida\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ação padrão\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acțiune implicită\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Действие по умолчанию\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Predvolená akcia\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podrazumevana radnja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standardåtgärd\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Varsayılan eylem\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Стандартна дія\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mặc định\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"默认动作\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"預設動作\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"預設動作\"\n          }\n        }\n      }\n    },\n    \"Delete\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee uit\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izbriši\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suprimeix\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smazat\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slet\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Löschen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διαγραφή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poista\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מחק\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Törlés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hapus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elimina\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"削除\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"삭제\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖျက်ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slett\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verwijderen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usuń\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apagar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apagar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ștergere\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удалить\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odstrániť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izbriši\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ta bort\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sil\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Xóa\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除\"\n          }\n        }\n      }\n    },\n    \"Delete Configuration?\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee Konfigurasie uit?\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف الإعدادات؟\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izbrisati konfiguraciju?\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suprimir la configuració?\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smazat konfiguraci?\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slet konfiguration?\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration löschen?\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διαγραφή διαμόρφωσης;\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"¿Eliminar la configuración?\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poistetaanko määritys?\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer la configuration ?\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מחק תצורה?\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguráció törlése?\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hapus Konfigurasi?\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminare la configurazione?\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定を削除しますか？\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 삭제?\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration ကို ဖျက်မည်လား?\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slette konfigurasjon?\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie verwijderen?\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usunąć konfigurację?\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apagar Configuração?\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Excluir Configuração?\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ștergere configurație?\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удалить конфигурацию?\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odstrániť konfiguráciu?\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izbriši konfiguraciju?\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ta bort konfigurationen?\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırmayı Sil?\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити конфігурацію?\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Xóa Cấu hình?\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除配置？\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除設定？\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除設定？\"\n          }\n        }\n      }\n    },\n    \"Delete…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee uit…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حذف…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izbriši…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suprimeix…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smazat…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slet…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Löschen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διαγραφή…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eliminar…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poista…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Supprimer…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מחק…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Törlés…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hapus…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elimina…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"削除…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"삭제…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖျက်ရန်…\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slett…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verwijderen…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usuń…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apagar…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Excluir…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ștergere…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удалить…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odstrániť…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izbriši…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ta bort…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sil…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Видалити…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Xóa…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"删除…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"刪除…\"\n          }\n        }\n      }\n    },\n    \"Direct and immediate, with a short controlled tail.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direk en onmiddellik, met 'n kort beheerde uitloop.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مباشر وفوري، مع ذيل قصير ومتحكم به.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direktno i trenutno, s kratkim kontrolisanim završetkom.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Directe i immediat, amb una cua curta i controlada.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přímé a okamžité, s krátkým kontrolovaným dozvukem.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direkte og umiddelbar med en kort, kontrolleret hale.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direkt und unmittelbar, mit kurzem kontrolliertem Nachlauf.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Άμεσο και ακαριαίο, με σύντομη ελεγχόμενη ουρά.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Directo e inmediato, con una cola corta y controlada.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suora ja välitön, lyhyellä hallitulla hännällä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direct et immédiat, avec une courte traîne maîtrisée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ישיר ומיידי, עם זנב קצר ומבוקר.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Közvetlen és azonnali, rövid, kontrollált lecsengéssel.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Langsung dan seketika, dengan ekor singkat yang terkontrol.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diretto e immediato, con una coda breve e controllata.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"直接的で即応性が高く、短く制御された余韻があります。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"직접적이고 즉각적이며, 짧고 제어된 꼬리가 있습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တိုက်ရိုက်ပြီး ချက်ချင်းတုံ့ပြန်ကာ၊ ထိန်းထားသော အတိုအရှည် အဆုံးပိုင်းပါသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direkte og umiddelbar, med en kort og kontrollert hale.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direct en onmiddellijk, met een korte gecontroleerde uitloop.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bezpośredni i natychmiastowy, z krótkim, kontrolowanym ogonem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direto e imediato, com uma cauda curta e controlada.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direto e imediato, com uma cauda curta e controlada.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direct și imediat, cu o coadă scurtă și controlată.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прямой и мгновенный, с коротким контролируемым хвостом.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Priamy a okamžitý, s krátkym kontrolovaným dozvukom.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Директан и тренутан, са кратким контролисаним завршетком.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direkt och omedelbar, med en kort kontrollerad svans.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doğrudan ve anında, kısa ve kontrollü bir kuyrukla.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прямий і миттєвий, із коротким контрольованим хвостом.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trực tiếp và tức thì, với phần đuôi ngắn và có kiểm soát.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"直接且即时，带有短而可控的尾段。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"直接且即時，帶有短而可控的尾段。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"直接且即時，帶有短而可控的尾段。\"\n          }\n        }\n      }\n    },\n    \"Disable pointer acceleration\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deaktiveer wyserversnelling\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تعطيل تسارع المؤشر\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onemogući ubrzavanje pokazivača\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desactiva l'acceleració del punter\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deaktivovat zrychlení kurzoru\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deaktiver markøracceleration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeigerbeschleunigung deaktivieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Απενεργοποίηση επιτάχυνσης δείκτη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deshabilitar aceleración del cursor\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poista osoittimen kiihdytys käytöstä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactiver l'accélération du pointeur\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בטל תאוצת סמן העכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutatógyorsítás letiltása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nonaktifkan akselerasi penunjuk\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disabilita l'accelerazione del puntatore\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ポインター加速を無効にする。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"포인터 가속 비활성화\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညွှန်ပြကိရိယာအရှိန်ကို ပိတ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deaktiver pekeraksellerasjon\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanwijzerversnelling uitschakelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłącz przyspieszenie wskaźnika\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desativar aceleração do cursor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desabilitar aceleração de ponteiro\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dezactivează accelerația cursorului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отключить ускорение курсора\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vypnúť zrýchlenie ukazovateľa\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onemogući ubrzanje pokazivača\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inaktivera pekarkacceleration\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşaretçi ivmesini devre dışı bırak\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути прискорення курсору\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tắt gia tốc con trỏ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用指针加速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用指標加速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"禁用指標加速度\"\n          }\n        }\n      }\n    },\n    \"Display\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertoon\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"شاشة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekran\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pantalla\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Displej\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skærm\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Display\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Οθόνη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitor\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näyttö\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תצוגה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kijelző\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Layar\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schermo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ディスプレイ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"디스플레이\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Display\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skjerm\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weergave\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyświetlacz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monitor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tela\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișaj\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Экран\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Displej\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekran\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skärm\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekran\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дисплей\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Màn hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示器\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示器\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"螢幕\"\n          }\n        }\n      }\n    },\n    \"Distance\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afstand\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"المسافة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udaljenost\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distància\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vzdálenost\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afstand\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distanz\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Απόσταση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distancia\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etäisyys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distance\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מרחק\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Távolság\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jarak\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distanza\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距離\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"간격\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အကွာအဝေး\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avstand\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afstand\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dystans\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distância\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distância\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distanță\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Расстояние\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vzdialenosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udaljenost\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avstånd\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mesafe\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відстань\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khoảng cách\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距离\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距離\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距離\"\n          }\n        }\n      }\n    },\n    \"Distance must be \\\"auto\\\" or a number or a string representing value and unit\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afstand moet \\\"auto\\\" of 'n getal of 'n string wees wat waarde en eenheid voorstel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يجب أن تكون المسافة \\\"auto\\\" أو رقمًا أو سلسلة تمثل القيمة والوحدة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udaljenost mora biti \\\"auto\\\", broj ili tekst koji predstavljaju mjeru i jedinicu mjere\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La distància ha de ser \\\"auto\\\" o un número o una cadena que representi el valor i la unitat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vzdálenost musí být „auto“ nebo číslo nebo řetězec reprezentující hodnotu a jednotku\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afstand skal være \\\"auto\\\" eller et tal eller en streng, der repræsenterer værdi og enhed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Der Abstand muss „auto“ oder eine Zahl oder eine Zeichenfolge sein, die Wert und Einheit darstellt\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Η απόσταση πρέπει να είναι \\\"auto\\\" ή ένας αριθμός ή μια συμβολοσειρά που αντιπροσωπεύει τιμή και μονάδα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La distancia debe ser \\\"auto\\\", un número o una cadena representando valor y unidad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etäisyyden on oltava \\\"auto\\\" tai numero tai arvoa ja yksikköä edustava merkkijono\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La distance doit être « auto » ou un nombre ou une chaîne représentant la valeur et l’unité\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"המרחק חייב להיות \\\"auto\\\" או מספר או מחרוזת המייצגת ערך ויחידה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A távolságnak \\\"auto\\\" vagy számnak, vagy az értéket és mértékegységet reprezentáló sztringnek kell lennie\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jarak harus berupa \\\"auto\\\" atau angka atau string yang mewakili nilai dan satuan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La distanza deve essere \\\"auto\\\" o un numero o una stringa che rappresenta valore e unità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距離は「auto」または数値、あるいは値と単位を表す文字列である必要があります。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"간격은 \\\"자동\\\"이거나 값과 단위를 나타내는 숫자 또는 문자열이어야 합니다\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အကွာအဝေးသည် \\\"auto\\\" သို့မဟုတ် နံပါတ်တစ်ခု သို့မဟုတ် တန်ဖိုးနှင့် ယူနစ်ကို ကိုယ်စားပြုသည့် စာကြောင်းတစ်ခု ဖြစ်ရမည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avstand må være «auto», et tall eller en streng som representerer verdi og enhet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afstand moet \\\"auto\\\" of een getal of een tekenreeks zijn die waarde en eenheid vertegenwoordigt\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odległość musi być „auto” lub liczbą albo ciągiem znaków reprezentującym wartość i jednostkę\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A distância deve ser \\\"auto\\\" ou um número ou uma string representando valor e unidade\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A distância deve ser \\\"auto\\\" ou um número ou uma string representando valor e unidade\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Distanța trebuie să fie „auto” sau un număr sau un șir care reprezintă valoarea și unitatea\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Расстояние должно быть «auto» или числом или строкой, представляющей значение и единицу измерения\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vzdialenosť musí byť „auto“ alebo číslo alebo reťazec reprezentujúci hodnotu a jednotku\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udaljenost mora biti „auto“ ili broj ili niz koji predstavlja vrednost i jedinicu\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avstånd måste vara \\\"auto\\\" eller ett nummer eller en sträng som representerar värde och enhet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mesafe \\\"otomatik\\\" veya bir sayı veya değeri ve birimi temsil eden bir dize olmalıdır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відстань має бути \\\"auto\\\" або числом чи рядком, що представляє значення та одиницю вимірювання\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khoảng cách phải là \\\"auto\\\" hoặc một số hoặc một chuỗi đại diện cho giá trị và đơn vị\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距离必须是“auto”、数字或一个代表值和单位的字符串\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距離必須是「auto」或數字，或代表值與單位的字串\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"距離必須是「auto」或數字，或代表數值和單位的字串\"\n          }\n        }\n      }\n    },\n    \"Donate\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skenk\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تبرع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doniraj\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dona\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přispět\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Donér\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spenden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δωρεά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Donar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lahjoita\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faire un don\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תרומה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Támogatás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Donasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dona\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"支援する\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"후원하기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လှူရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doner\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doneer\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wesprzyj\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Donați\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отблагодарить\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podporiť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doniraj\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Donera\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bağış yap\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Підтримати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ủng hộ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捐赠\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捐贈\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捐贈\"\n          }\n        }\n      }\n    },\n    \"Due to system limitations, this device may not support adjusting Pointer Speed on newer versions of macOS.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As gevolg van stelselbeperkings, ondersteun hierdie toestel dalk nie die aanpassing van wysersnelheid op nuwer weergawes van macOS nie.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بسبب قيود النظام، قد لا يدعم هذا الجهاز ضبط سرعة المؤشر في الإصدارات الأحدث من macOS.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zbog sistemskih ograničenja, ovaj uređaj možda ne podržava podešavanje brzine pokazivača na novijim verzijama macOS-a.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A causa de les limitacions del sistema, aquest dispositiu pot no suportar l'ajust de la velocitat del punter en versions més recents de macOS.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvůli systémovým omezením nemusí toto zařízení podporovat úpravu rychlosti ukazatele v novějších verzích macOS.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"På grund af systembegrænsninger understøtter denne enhed muligvis ikke justering af markørhastighed på nyere versioner af macOS.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aufgrund von Systembeschränkungen unterstützt dieses Gerät möglicherweise nicht die Anpassung der Zeigergeschwindigkeit in neueren Versionen von macOS.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Λόγω περιορισμών συστήματος, αυτή η συσκευή ενδέχεται να μην υποστηρίζει την προσαρμογή της ταχύτητας του δείκτη σε νεότερες εκδόσεις του macOS.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Debido a limitaciones del sistema, es posible que este dispositivo no admita el ajuste de la velocidad del puntero en las versiones más recientes de macOS.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Järjestelmän rajoitusten vuoksi tämä laite ei ehkä tue osoittimen nopeuden säätämistä macOS:n uudempien versioiden kanssa.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En raison de limitations système, ce périphérique pourrait ne pas prendre en charge le réglage de la vitesse du pointeur sur les versions plus récentes de macOS.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"עקב מגבלות מערכת, ייתכן שמכשיר זה אינו תומך בהתאמת מהירות המצביע בגרסאות חדשות יותר של macOS.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rendszerkorlátozások miatt ez az eszköz nem támogatja a Mutató sebességének beállítását a macOS újabb verzióin.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Karena keterbatasan sistem, perangkat ini mungkin tidak mendukung penyesuaian Kecepatan Penunjuk pada versi macOS yang lebih baru.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A causa di limitazioni di sistema, questo dispositivo potrebbe non supportare la regolazione della velocità del puntatore nelle versioni più recenti di macOS.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"システム上の制限により、このデバイスはmacOSの新しいバージョンでポインター速度の調整をサポートしていない場合があります。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시스템 제한으로 인해 이 기기는 최신 버전의 macOS에서 포인터 속도 조정을 지원하지 않을 수 있습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"စနစ်၏ ကန့်သတ်ချက်များကြောင့်၊ ဤစက်ပစ္စည်းသည် macOS ၏ နောက်ဆုံးဗားရှင်းများတွင် Pointer Speed ကို ချိန်ညှိခြင်းကို မထောက်ပံ့နိုင်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"På grunn av systembegrensninger støtter kanskje ikke denne enheten justering av Pekerhastighet på nyere versjoner av macOS.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vanwege systeemprestaties ondersteunt dit apparaat mogelijk niet het aanpassen van de aanwijzersnelheid op nieuwere versies van macOS.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ze względu na ograniczenia systemowe to urządzenie może nie obsługiwać dostosowywania prędkości wskaźnika w nowszych wersjach systemu macOS.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Devido a limitações do sistema, este dispositivo pode não suportar o ajuste da Velocidade do Ponteiro em versões mais recentes do macOS.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Devido a limitações do sistema, este dispositivo pode não suportar o ajuste da Velocidade do Ponteiro em versões mais recentes do macOS.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Din cauza limitărilor sistemului, acest dispozitiv s-ar putea să nu suporte ajustarea vitezei indicatorului pe versiunile mai noi de macOS.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Из-за системных ограничений это устройство может не поддерживать настройку скорости указателя в новых версиях macOS.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Z dôvodu systémových obmedzení toto zariadenie nemusí podporovať úpravu rýchlosti ukazovateľa v novších verziách macOS.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zbog sistemskih ograničenja, ovaj uređaj možda ne podržava podešavanje brzine pokazivača na novijim verzijama macOS-a.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"På grund av systembegränsningar kanske den här enheten inte stöder justering av pekarens hastighet i nyare versioner av macOS.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sistem sınırlamaları nedeniyle, bu aygıt macOS'un daha yeni sürümlerinde İşaretçi Hızını ayarlamayı desteklemeyebilir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Через системні обмеження цей пристрій може не підтримувати налаштування швидкості вказівника в новіших версіях macOS.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Do hạn chế của hệ thống, thiết bị này có thể không hỗ trợ điều chỉnh Tốc độ Con trỏ trên các phiên bản macOS mới hơn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"由于系统限制，此设备可能不支持调整较新 macOS 版本上的指针速度。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"由於系統限制，此裝置可能不支援較新 macOS 版本中的指標速度調整。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"由於系統限制，此裝置可能不支援在較新版本的 macOS 中調整指標速度。\"\n          }\n        }\n      }\n    },\n    \"Ease In\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geleidelike begin\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postepeni početak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pozvolný náběh\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blød start\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sanfter Start\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ομαλή έναρξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pehmeä alku\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lágy indulás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan halus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione graduale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズイン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖြည်းဖြည်း အရှိန်တက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Myk start\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geleidelijke start\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne narastanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare la început\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn start\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Başlangıç\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng dần\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入\"\n          }\n        }\n      }\n    },\n    \"Ease In Cubic\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubiese geleidelike begin\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي تكعيبي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubični postepeni početak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau cúbica\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubický pozvolný náběh\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk blød start\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubischer sanfter Start\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κυβική ομαλή έναρξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave cúbica\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuutiollinen pehmeä alku\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce cubique\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית קובייתית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Köbös lágy indulás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan halus kubik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione graduale cubica\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズイン・キュービック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인 큐빅\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cubic ဖြည်းဖြည်း အရှိန်တက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk myk start\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubische geleidelijke start\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sześcienne łagodne narastanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave cúbica\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave cúbica\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare la început (cubic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон (кубический)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie (kubické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање (кубно)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn start (kubisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Başlangıç (Kübik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін (кубічний)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng dần (bậc ba)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入（三次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入（三次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入（三次）\"\n          }\n        }\n      }\n    },\n    \"Ease In Out\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geleidelike begin en einde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع ثم تباطؤ تدريجي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postepeni početak i završetak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada i sortida suaus\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pozvolný náběh a doznění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blød start og afslutning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sanfter Start und sanftes Ende\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ομαλή έναρξη και λήξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada y salida suaves\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pehmeä alku ja loppu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée et sortie douces\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה וסיום הדרגתיים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lágy indulás és lecsengés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan dan perlambatan halus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione e rallentamento graduali\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズインアウト\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인 아웃\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖြည်းဖြည်း အရှိန်တက်နှင့် လျော့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Myk start og avslutning\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geleidelijke start en uitloop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne narastanie i wyhamowanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e desaceleração suaves\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e desaceleração suaves\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare și încetinire lină\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон и замедление\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie a spomalenie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање и успоравање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn in och ut\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Giriş ve Çıkış\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін і сповільнення\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng rồi giảm dần\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入缓出\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入緩出\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入緩出\"\n          }\n        }\n      }\n    },\n    \"Ease In Out Cubic\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubiese geleidelike begin en einde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع وتباطؤ تدريجي تكعيبي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubični postepeni početak i završetak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada i sortida suaus cúbiques\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubický pozvolný náběh a doznění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk blød start og afslutning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubischer sanfter Start und sanftes Ende\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κυβική ομαλή έναρξη και λήξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada y salida suaves cúbicas\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuutiollinen pehmeä alku ja loppu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée et sortie douces cubiques\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה וסיום הדרגתיים קובייתיים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Köbös lágy indulás és lecsengés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan/perlambatan kubik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione e rallentamento cubici\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズインアウト・キュービック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인 아웃 큐빅\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cubic ဖြည်းဖြည်း အရှိန်တက်နှင့် လျော့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk myk start og avslutning\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubische geleidelijke start en uitloop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sześcienne łagodne narastanie i wyhamowanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e desaceleração cúbicas\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e desaceleração cúbicas\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare și încetinire lină (cubic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон и замедление (кубическое)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie a spomalenie (kubické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање и успоравање (кубно)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn in och ut (kubisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Giriş ve Çıkış (Kübik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін і сповільнення (кубічне)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng rồi giảm dần (bậc ba)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入缓出（三次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入緩出（三次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入緩出（三次）\"\n          }\n        }\n      }\n    },\n    \"Ease In Out Quartic\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartiese geleidelike begin en einde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع وتباطؤ تدريجي رباعي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartični postepeni početak i završetak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada i sortida suaus quàrtiques\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartický pozvolný náběh a doznění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk blød start og afslutning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartischer sanfter Start und sanftes Ende\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τεταρτοβάθμια ομαλή έναρξη και λήξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada y salida suaves cuárticas\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neljännen asteen pehmeä alku ja loppu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée et sortie douces quartiques\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה וסיום הדרגתיים ממעלה רביעית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Negyedfokú lágy indulás és lecsengés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan/perlambatan kuartik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione e rallentamento quartici\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズインアウト・クォーティック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인 아웃 쿼틱\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartic ဖြည်းဖြည်း အရှိန်တက်နှင့် လျော့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk myk start og avslutning\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartische geleidelijke start en uitloop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne narastanie i wyhamowanie czwartego stopnia\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e desaceleração quárticas\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração e desaceleração quárticas\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare și încetinire lină (cvartic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон и замедление (квартическое)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie a spomalenie (kvartické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање и успоравање (квартично)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn in och ut (kvartisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Giriş ve Çıkış (Kuartik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін і сповільнення (квартичне)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng rồi giảm dần (bậc bốn)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入缓出（四次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入緩出（四次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入緩出（四次）\"\n          }\n        }\n      }\n    },\n    \"Ease In Quad\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwadratiese geleidelike begin\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي تربيعي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratni postepeni početak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau quadràtica\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratický pozvolný náběh\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratisk blød start\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quadratischer sanfter Start\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τετραγωνική ομαλή έναρξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave cuadrática\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neliöllinen pehmeä alku\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce quadratique\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית ריבועית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratikus lágy indulás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan halus kuadratik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione graduale quadratica\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズイン・クアッド\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인 쿼드\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quad ဖြည်းဖြည်း အရှိန်တက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratisk myk start\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwadratische geleidelijke start\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwadratowe łagodne narastanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave quadrática\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave quadrática\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare la început (cvadratic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон (квадратичный)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie (kvadratické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање (квадратно)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn start (kvadratisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Başlangıç (Kuadratik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін (квадратичний)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng dần (bậc hai)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入（二次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入（二次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入（二次）\"\n          }\n        }\n      }\n    },\n    \"Ease In Quartic\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartiese geleidelike begin\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي رباعي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartični postepeni početak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau quartica\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartický pozvolný náběh\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk blød start\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartischer sanfter Start\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τεταρτοβάθμια ομαλή έναρξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave cuártica\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neljännen asteen pehmeä alku\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce quartique\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית ממעלה רביעית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Negyedfokú lágy indulás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Percepatan halus kuartik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione graduale quartica\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズイン・クォーティック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 인 쿼틱\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartic ဖြည်းဖြည်း အရှိန်တက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk myk start\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartische geleidelijke start\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne narastanie czwartego stopnia\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave quártica\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração suave quártica\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare la început (cvartic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный разгон (квартический)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé zrýchlenie (kvartické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено убрзање (квартично)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn start (kvartisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Başlangıç (Kuartik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний розгін (квартичний)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng dần (bậc bốn)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓入（四次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入（四次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩入（四次）\"\n          }\n        }\n      }\n    },\n    \"Ease Out\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geleidelike einde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تباطؤ تدريجي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postepeni završetak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sortida suau\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pozvolné doznění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blød afslutning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sanftes Ende\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ομαλή λήξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Salida suave\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pehmeä loppu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sortie douce\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סיום הדרגתי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lágy lecsengés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perlambatan halus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rallentamento graduale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズアウト\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 아웃\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖြည်းဖြည်း အရှိန်လျော့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Myk avslutning\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geleidelijke uitloop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne wyhamowanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desaceleração suave\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desaceleração suave\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Încetinire la final\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавное замедление\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé spomalenie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено успоравање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn avslutning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Bitiş\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавне сповільнення\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giảm dần\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓出\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩出\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩出\"\n          }\n        }\n      }\n    },\n    \"Ease Out Cubic\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubiese geleidelike einde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تباطؤ تدريجي تكعيبي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubični postepeni završetak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sortida suau cúbica\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubické pozvolné doznění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk blød afslutning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisches sanftes Ende\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κυβική ομαλή λήξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Salida suave cúbica\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuutiollinen pehmeä loppu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sortie douce cubique\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סיום הדרגתי קובייתי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Köbös lágy lecsengés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perlambatan halus kubik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rallentamento graduale cubico\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズアウト・キュービック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 아웃 큐빅\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cubic ဖြည်းဖြည်း အရှိန်လျော့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk myk avslutning\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubische geleidelijke uitloop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sześcienne łagodne wyhamowanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desaceleração suave cúbica\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desaceleração suave cúbica\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Încetinire la final (cubic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавное замедление (кубическое)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé spomalenie (kubické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено успоравање (кубно)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn avslutning (kubisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Bitiş (Kübik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавне сповільнення (кубічне)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giảm dần (bậc ba)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓出（三次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩出（三次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩出（三次）\"\n          }\n        }\n      }\n    },\n    \"Ease Out Quartic\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartiese geleidelike einde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تباطؤ تدريجي رباعي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartični postepeni završetak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sortida suau quartica\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartické pozvolné doznění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk blød afslutning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartisches sanftes Ende\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τεταρτοβάθμια ομαλή λήξη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Salida suave cuártica\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neljännen asteen pehmeä loppu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sortie douce quartique\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סיום הדרגתי ממעלה רביעית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Negyedfokú lágy lecsengés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perlambatan halus kuartik\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rallentamento graduale quartico\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"イーズアウト・クォーティック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이즈 아웃 쿼틱\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartic ဖြည်းဖြည်း အရှိန်လျော့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk myk avslutning\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartische geleidelijke uitloop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne wyhamowanie czwartego stopnia\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desaceleração suave quártica\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desaceleração suave quártica\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Încetinire la final (cvartic)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавное замедление (квартическое)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulé spomalenie (kvartické)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Постепено успоравање (квартично)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lugn avslutning (kvartisk)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşak Bitiş (Kuartik)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавне сповільнення (квартичне)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giảm dần (bậc bốn)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缓出（四次）\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩出（四次）\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩出（四次）\"\n          }\n        }\n      }\n    },\n    \"Ease-in cubic with a stronger progressive build.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubiese geleidelike begin met 'n sterker progressiewe opbou.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي تكعيبي مع تصاعد تدريجي أقوى.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubični postepeni početak sa snažnijim progresivnim porastom.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau cúbica amb una progressió més marcada.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubický pozvolný náběh se silnějším postupným zesílením.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk blød start met een sterker progressiewe opbou.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubischer sanfter Start mit stärkerem progressivem Aufbau.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κυβική ομαλή έναρξη με πιο έντονη προοδευτική ενίσχυση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave cúbica con una progresión más marcada.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuutiollinen pehmeä alku vahvemmalla asteittaisella kasvulla.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce cubique avec une montée progressive plus marquée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית קובייתית עם בנייה הדרגתית חזקה יותר.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Köbös lágy indulás, erőteljesebb fokozatos felépüléssel.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in kubik dengan peningkatan progresif yang lebih kuat.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in cubico con una progressione più marcata.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"より力強く段階的に立ち上がる、キュービックのイーズインです。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"더 강하게 점진적으로 쌓이는 큐빅 이즈 인입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပိုအားကောင်းသော အဆင့်လိုက် အရှိန်တက်မှုရှိသည့် cubic ease-in ဖြစ်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk myk start med tydeligere progressiv oppbygging.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubische geleidelijke start met een sterkere progressieve opbouw.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sześcienne łagodne narastanie z mocniejszym progresywnym wzrostem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in cúbico com uma progressão mais forte.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in cúbico com uma progressão mais forte.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in cubic, cu o acumulare progresivă mai puternică.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кубический ease-in с более сильным прогрессивным нарастанием.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubické ease-in so silnejším postupným nábehom.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кубно ease-in убрзање са јачим постепеним растом.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kubisk ease-in med starkare progressiv uppbyggnad.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daha güçlü, kademeli bir yükselişe sahip kübik ease-in.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кубічний ease-in із сильнішим поступовим наростанням.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in bậc ba với đà tăng lũy tiến mạnh hơn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次缓入，渐进式增强更明显。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次緩入，漸進式增強更明顯。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次緩入，漸進式增強更明顯。\"\n          }\n        }\n      }\n    },\n    \"Ease-in quad with a noticeable but manageable ramp-up.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwadratiese geleidelike begin met 'n merkbare maar hanteerbare opbou.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي تربيعي مع تصاعد ملحوظ لكن يمكن التحكم به.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratni postepeni početak s primjetnim, ali upravljivim porastom.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau quadràtica amb una pujada notable però controlable.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratický pozvolný náběh s výrazným, ale zvládnutelným zesílením.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratisk blød start med en mærkbar, men håndterbar opbygning.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quadratischer sanfter Start mit spürbarem, aber gut kontrollierbarem Anstieg.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τετραγωνική ομαλή έναρξη με αισθητή αλλά διαχειρίσιμη επιτάχυνση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave cuadrática con una aceleración perceptible pero manejable.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neliöllinen pehmeä alku, jossa kiihtyminen on tuntuva mutta hallittava.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce quadratique avec une montée sensible mais maîtrisable.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית ריבועית עם עלייה מורגשת אך נשלטת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratikus lágy indulás, érezhető, de jól kezelhető felfutással.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in kuadratik dengan peningkatan yang terasa namun tetap mudah dikendalikan.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in quadratico con una progressione evidente ma gestibile.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立ち上がりを感じやすい一方で扱いやすい、クアッドのイーズインです。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"분명히 느껴지지만 다루기 쉬운 상승감을 가진 쿼드 이즈 인입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"သိသာပေမယ့် ထိန်းရလွယ်သော အရှိန်တက်မှုရှိသည့် quad ease-in ဖြစ်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratisk myk start med merkbar, men håndterbar oppbygging.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwadratische geleidelijke start met een merkbare maar beheersbare opbouw.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwadratowe łagodne narastanie z wyraźnym, ale łatwym do opanowania wzrostem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in quadrático com uma aceleração notória, mas controlável.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in quadrático com uma aceleração perceptível, mas controlável.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in cvadratic, cu o acumulare vizibilă, dar ușor de controlat.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квадратичный ease-in с заметным, но управляемым нарастанием.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratické ease-in s výrazným, no zvládnuteľným nábehom.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квадратно ease-in убрзање са приметним, али контролисаним растом.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvadratisk ease-in med märkbar men hanterbar uppbyggnad.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fark edilir ama yönetilebilir bir yükselişe sahip kuadratik ease-in.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квадратичний ease-in із помітним, але керованим наростанням.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in bậc hai với độ tăng rõ rệt nhưng vẫn dễ kiểm soát.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"二次缓入，起势明显但仍易于控制。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"二次緩入，起勢明顯但仍易於控制。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"二次緩入，起勢明顯但仍易於控制。\"\n          }\n        }\n      }\n    },\n    \"Ease-in quartic with the strongest front-loaded ramp.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartiese geleidelike begin met die sterkste voorlaaide opbou.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع تدريجي رباعي بأقوى تصاعد متركز في البداية.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartični postepeni početak s najjačim početnim porastom.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suau quartica amb la pujada inicial més marcada.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartický pozvolný náběh s nejsilnějším zesílením na začátku.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk blød start med den kraftigste indledende opbygning.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartischer sanfter Start mit dem stärksten Anstieg zu Beginn.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τεταρτοβάθμια ομαλή έναρξη με την πιο έντονη αρχική επιτάχυνση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada suave cuártica con la aceleración inicial más fuerte.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neljännen asteen pehmeä alku vahvimmalla etupainotteisella kiihtymisellä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée douce quartique avec la montée initiale la plus marquée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה הדרגתית ממעלה רביעית עם העלייה החזקה ביותר בתחילת התנועה.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Negyedfokú lágy indulás a legerősebb kezdeti felfutással.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in kuartik dengan peningkatan awal paling kuat.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in quartico con l'accelerazione iniziale più marcata.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"序盤の立ち上がりが最も強い、クォーティックのイーズインです。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"초반 상승이 가장 강한 쿼틱 이즈 인입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အစပိုင်း အရှိန်တက်မှု အပြင်းထန်ဆုံးဖြစ်သော quartic ease-in ဖြစ်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk myk start med den kraftigste tidlige oppbyggingen.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartische geleidelijke start met de sterkste opbouw aan het begin.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne narastanie czwartego stopnia z najmocniejszym początkiem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in quártico com a aceleração inicial mais forte.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in quártico com a aceleração inicial mais forte.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in cvartic, cu cea mai puternică acumulare la început.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квартический ease-in с самым сильным начальным нарастанием.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartické ease-in s najsilnejším úvodným nábehom.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квартично ease-in убрзање са најјачим почетним растом.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk ease-in med den starkaste inledande uppbyggnaden.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En güçlü ön yüklemeli yükselişe sahip kuartik ease-in.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квартичний ease-in з найсильнішим початковим наростанням.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in bậc bốn với mức tăng đầu vào mạnh nhất.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次缓入，前段增幅最强。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次緩入，前段增幅最強。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次緩入，前段增幅最強。\"\n          }\n        }\n      }\n    },\n    \"Edit\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wysig\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تحرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uredi\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edita\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Upravit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rediger\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bearbeiten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επεξεργασία\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muokkaa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Éditer\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ערוך\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szerkesztés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edit\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifica\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"編集\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"편집\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြင်ဆင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rediger\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bewerken\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edytuj\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Редактировать\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Upraviť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uredi\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Redigera\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Düzenle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Редагувати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sửa\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"编辑\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"編輯\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"編輯\"\n          }\n        }\n      }\n    },\n    \"Editable\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bewerkbaar\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قابل للتعديل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uredivo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editable\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Upravitelné\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Redigerbar\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bearbeitbar\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επεξεργάσιμο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editable\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muokattavissa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifiable\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ניתן לעריכה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szerkeszthető\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dapat diedit\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modificabile\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"編集可能\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"편집 가능\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တည်းဖြတ်နိုင်သည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Redigerbar\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bewerkbaar\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edytowalny\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editável\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editável\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Editabil\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Редактируемый\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Upraviteľné\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Može se urediti\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Redigerbar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Düzenlenebilir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Редаговано\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Có thể chỉnh sửa\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"可编辑\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"可編輯\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"可編輯\"\n          }\n        }\n      }\n    },\n    \"Enable autoscroll\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiveer outomatiese blaai\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تمكين التمرير التلقائي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući automatsko pomicanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilita el desplaçament automàtic\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povolit automatické rolování\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivér automatisk rulning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatisches Scrollen aktivieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενεργοποίηση αυτόματης κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activar desplazamiento automático\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ota automaattinen vieritys käyttöön\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer le défilement automatique\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אפשר גלילה אוטומטית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatikus görgetés engedélyezése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktifkan gulir otomatis\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abilita scorrimento automatico\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"オートスクロールを有効にする\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"자동 스크롤 활성화\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက် scroll ကို ဖွင့်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiver autoskroll\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Automatisch scrollen inschakelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włącz automatyczne przewijanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar rolagem automática\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar rolagem automática\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activare derulare automată\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Включить автопрокрутку\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povoliť automatické rolovanie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući automatsko pomeranje\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivera autoscroll\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otomatik kaydırmayı etkinleştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкнути автопрокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bật tự động cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用自动滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用自動捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用自動捲動\"\n          }\n        }\n      }\n    },\n    \"Enable gesture button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiveer gebaar knoppie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تمكين زر الإيماءات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući dugme za gestu\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilita el botó de gestos\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povolit tlačítko gesta\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivér gestusknap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gesten-Schaltfläche aktivieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενεργοποίηση κουμπιού χειρονομίας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activar botón de gesto\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ota elepainike käyttöön\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer le bouton de geste\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אפשר לחצן מחוות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Érintés gomb engedélyezése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktifkan tombol gestur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abilita pulsante gesto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ジェスチャーボタンを有効にする\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"제스처 버튼 활성화\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမူအယာ ခလုတ်ကို ဖွင့်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiver gestknapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebarenknop inschakelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włącz przycisk gestów\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar botão de gesto\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar botão de gesto\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activare buton gest\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Включить кнопку жестов\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povoliť tlačidlo gesta\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući dugme za gestove\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivera gestknapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hareket düğmesini etkinleştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкнути кнопку жестів\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bật nút cử chỉ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用手势按钮\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用手勢按鈕\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用手勢按鈕\"\n          }\n        }\n      }\n    },\n    \"Enable universal back and forward\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiveer universele agter en vooruit\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تمكين الرجوع للأمام والخلف بشكل عام\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući univerzalne naprijed-nazad tipke\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilita el botó enrere i endavant universal\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivovat univerzální přecházení zpět a dopředu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivér universel frem og tilbage\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Universelles Vor und Zurück aktivieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενεργοποίηση λειτουργίας πίσω και εμπρός καθολικά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar retroceso y avance universal\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ota yleinen edestakaisin-toiminto käyttöön\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer l'option universelle pour revenir et avancer de pages\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הפעל חזרה והתקדמות באופן גלובלי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Univerzális vissza és előre engedélyezése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktifkan maju dan mundur universal\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abilitare avanti e indietro universale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"システム全般の戻る・進むボタンを有効にする\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"범용 뒤로/앞으로 가기 활성화\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Windows အတိုင်း back and forward ထားရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiver universell tilbake og fremover\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Universeel achter en vooruit inschakelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włącz uniwersalne przejścia wstecz i do przodu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar avanço e retrocesso universal\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar retorno e avanço universal\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activați funcția universală înapoi și înainte\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Включить универсальные «назад» и «вперед»\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povoliť univerzálny posun dozadu a dopredu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući univerzalno napred i nazad\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivera universell bakåt och framåt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Evrensel ileri ve geriyi etkinleştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкніть універсальний «Уперед» і «Назад»\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sử dụng nút quay lại và chuyển tiếp chung\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用全局后退、前进\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用全局後退、前進\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用全局後退、前進\"\n          }\n        }\n      }\n    },\n    \"Enable verbose logging\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiveer gedetailleerde logging\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تمكين التسجيل المفصل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući detaljno logiranje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilita el registre detallat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povolit podrobné protokolování\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivér detaljeret logning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausführliche Protokollierung aktivieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενεργοποίηση αναλυτικής καταγραφής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar registro detallado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ota yksityiskohtainen kirjaaminen käyttöön\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer le journal détaillé\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הפעל לוגים מילוליים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Részletes naplózás engedélyezése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktifkan pencatatan terperinci\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Attiva logging dettagliato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"詳細ログを有効化\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"자세한 로그 활성화\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အသေးစိတ် မှတ်တမ်းတင်ခြင်းကို ဖွင့်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiver detaljert loggføring\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uitgebreide logboekregistratie inschakelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włącz szczegółowe logowanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar registro detalhado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar registro de eventos\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activare jurnalizare detaliată\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Включить подробное ведение журнала\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povoliť podrobné zaznamenávanie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Омогући детаљно евидентирање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivera detaljerad loggning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayrıntılı günlük kaydını etkinleştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкнути докладний журнал\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bật chế độ verbose\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用详细日志记录\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用詳細日誌記錄\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用詳細日誌記錄\"\n          }\n        }\n      }\n    },\n    \"Enabling this option will log all input events, which may increase CPU usage while using %@, but can be useful for troubleshooting.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deur hierdie opsie te aktiveer, sal alle invoergebeurtenisse aangeteken word, wat die SVE-gebruik kan verhoog terwyl %@ gebruik word, maar nuttig kan wees vir probleemoplossing.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سيؤدي تمكين هذا الخيار إلى تسجيل جميع أحداث الإدخال، مما قد يزيد من استخدام وحدة المعالجة المركزية أثناء استخدام %@، ولكنه قد يكون مفيدًا لاستكشاف الأخطاء وإصلاحها.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogućavanje ove opcije će logirati sve ulazne događaje, što može povećati korištenje procesora prilikom korištenja %@, ali može biti korisno za rješavanje problema.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar aquesta opció registrarà tots els esdeveniments d'entrada, cosa que pot augmentar l'ús de la CPU mentre s'utilitza %@, però pot ser útil per a la resolució de problemes.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povolení volby bude protokolovat všechny vstupní události, což může zatížit CPU při používání %@, ale může být užitečné při řešení potíží.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivering af denne indstilling vil logge alle input-begivenheder, hvilket kan øge CPU-forbruget mens du bruger %@, men kan være nyttigt til fejlfinding.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wenn diese Option aktiviert ist, werden alle Eingabeereignisse protokolliert, was die CPU-Auslastung während der Verwendung von %@ erhöhen, jedoch bei der Fehlersuche nützlich sein kann.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Η ενεργοποίηση αυτής της επιλογής θα καταγράφει όλα τα συμβάντα εισόδου, κάτι που μπορεί να αυξήσει τη χρήση της CPU κατά τη χρήση του %@, αλλά μπορεί να είναι χρήσιμη για την αντιμετώπιση προβλημάτων.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar esta opción registrará todos los eventos de entrada, lo que puede aumentar el uso de CPU al usar %@, pero puede ser útil para solucionar problemas.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tämän asetuksen käyttöönotto kirjaa kaikki syötetapahtumat, mikä voi lisätä suorittimen käyttöä käytettäessä %@, mutta voi olla hyödyllistä vianmäärityksessä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activer cette option va enregistrer tous les événements d'entrée, ce qui peut augmenter l'utilisation du processeur en utilisant %@, mais peut être utile pour le dépannage.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הפעלת אפשרות זו תעשה לוג לכל אירוע קלט, מה שיכול להגביר את השימוש ב-CPU כאשר משתמשים ב-%@, אבל יכול לעזור לפתרון בעיות.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ennek az opciónak az engedélyezése naplózza az összes beviteli eseményt, ami növelheti a CPU használatát a(z) %@ használata közben, de hasznos lehet a hibaelhárításhoz.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mengaktifkan opsi ini akan mencatat semua peristiwa masukan, yang dapat meningkatkan penggunaan CPU saat menggunakan %@, tetapi berguna untuk pemecahan masalah.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abilitando questa opzione verranno registrati tutti gli eventi di input. Questo potrebbe incrementare l'uso della CPU quando %@ è in esecuzione, ma può essere utile per la risoluzione dei problemi.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"このオプションを有効にすると、すべての入力イベントが記録されるため、 %@の使用中に CPU 使用率が増加する可能性がありますが、トラブルシューティングに役立ちます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이 옵션을 활성화하면 모든 입력 이벤트가 기록되며, 이는 %@를 사용하는 동안 CPU 사용량을 증가시킬 수 있지만 문제 해결에 유용할 수 있습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဤရွေးချယ်မှုကို ဖွင့်ခြင်းဖြင့် အားလုံးသော အသုံးပြုမှုဖြစ်ရပ်များကို မှတ်တမ်းတင်ပါမည်။ ၄င်းသည် %@ ကို အသုံးပြုနေစဉ် CPU အသုံးပြုမှုကို တိုးမြှင့်နိုင်ပါသည်၊ သို့သော် ပြဿနာများကို ဖြေရှင်းရန် အသုံးဝင်နိုင်ပါသည်။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktivering av dette alternativet vil logge alle inndatahendelser, noe som kan øke CPU-bruken mens du bruker %@, men kan være nyttig for feilsøking.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Het inschakelen van deze optie zal alle invoer-gebeurtenissen loggen, wat het CPU-gebruik kan verhogen terwijl je %@ gebruikt, maar kan nuttig zijn voor het oplossen van problemen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Włączenie tej opcji spowoduje rejestrowanie wszystkich zdarzeń wejściowych, co może zwiększyć użycie procesora podczas używania %@, ale może być użyteczne przy rozwiązywaniu problemów.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar esta opção registrará todos os eventos de entrada, o que pode aumentar o uso da CPU ao usar %@, mas pode ser útil para solução de problemas.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Habilitar esta opção irá registrar todos os eventos de entrada, o que pode aumnetar o uso de CPU enquanto utiliza %@ mas pode ser útil para solução de problemas.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activarea acestei opțiuni va înregistra toate evenimentele de intrare, ceea ce poate crește utilizarea procesorului în timp ce utilizați %@, dar poate fi utilă pentru depanare.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Включение этой опции влияет на запись в журнал всех входящих событий, что может увеличить нагрузку на ЦП при использовании %@, но будет полезно для поиска неполадок.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zapnutím tejto možnosti sa zaznamenajú všetky vstupné udalosti, čo môže zvýšiť využitie procesora pri používaní %@, ale môže to byť užitočné pri riešení problémov.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Омогућавање ове опције ће евидентирати све улазне догађаје, што може повећати коришћење ЦПУ-а током коришћења %@, али може бити корисно за решавање проблема.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Att aktivera detta alternativ loggar alla inmatningshändelser, vilket kan öka CPU-användningen när du använder %@, men kan vara användbart för felsökning.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bu seçeneğin etkinleştirilmesi, %@ kullanılırken CPU kullanımını arttırabilir, ancak sorun giderme için faydalı olabilecek tüm giriş olaylarını loglara kaydedecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увімкнення цього пункту призведе до реєстрації усіх подій введення, що може збільшити використання ЦП під час використання %@, але може бути корисним для пошуку та усунення несправностей.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bật tùy chọn này sẽ ghi nhật ký tất cả các sự kiện đầu vào, điều này có thể làm tăng mức sử dụng CPU khi sử dụng %@, nhưng có thể hữu ích cho việc khắc phục sự cố.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启用此选项将记录所有输入事件，这可能增加使用 %@ 时的 CPU 使用率，但有助于排除故障。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用此選項將記錄所有輸入事件，這可能增加使用 %@ 時的 CPU 使用率，但有助於排除故障。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟用此選項將記錄所有輸入事件，這可能增加使用 %@ 時的 CPU 使用率，但有助於排除故障。\"\n          }\n        }\n      }\n    },\n    \"Execute\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voer uit\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تنفيذ\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izvrši\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executa\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksekvér\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausführen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εκτέλεση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ejecutar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suorita\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exécuter\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הרץ\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Végrehajtás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jalankan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esegui\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"実行\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"실행\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လုပ်ဆောင်ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kjør\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uitvoeren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wykonaj\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выполнить\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vykonať\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Изврши\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kör\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yürütme\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Виконати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thực thi\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"执行\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行\"\n          }\n        }\n      }\n    },\n    \"Export logs\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voer logs uit\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تصدير السجلات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izvezi logove\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporta els registres\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportovat protokoly\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksporter logs\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Logdateien exportieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εξαγωγή αρχείων καταγραφής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar registros\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vie lokit\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporter les journaux\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ייצא לוגים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naplók exportálása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekspor log\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esporta i registri\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ログを取る\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"로그 내보내기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မှတ်တမ်းများကို export လုပ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksporter logger\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Logs exporteren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksportuj logi\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar registros\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar registros de eventos\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportare jurnale\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Экспорт логов\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportovať záznamy\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Извези евиденције\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportera loggar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Logları dışa aktar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Експортувати журнал\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trích xuất nhật ký\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"导出日志\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"匯出記錄\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"匯出記錄\"\n          }\n        }\n      }\n    },\n    \"Export the logs for the last 5 minutes.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voer die logs vir die laaste 5 minute uit.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تصدير السجلات لآخر 5 دقائق.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izvezi logove od zadnjih 5 minuta.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporta els registres dels últims 5 minuts.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportuje protokoly za posledních 5 minut.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksporter logfilerne for de sidste 5 minutter.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportieren der Logdateien für die letzten 5 Minuten.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εξαγωγή των αρχείων καταγραφής για τα τελευταία 5 λεπτά.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar los registros de los últimos 5 minutos.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vie viimeisten 5 minuutin lokit.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporter les journaux des 5 dernières minutes.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"יצא את הלוגים של ה-5 דקות האחרונות.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportálja a naplókat az elmúlt 5 percből.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekspor log 5 menit terakhir.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esporta i registri per gli ultimi 5 minuti.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"過去5分間のログを取る。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"지난 5분 동안 로그 내보내기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နောက်ဆုံး ၅ မိနစ်အတွင်းမှ မှတ်တမ်းများကို export လုပ်ပါ။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksporter logger fra de siste 5 minuttene.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exporteer de logs van de laatste 5 minuten.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksportuj logi z ostatnich 5 minut.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar os registros dos últimos 5 minutos.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportar registros de eventos dos últimos 5 minutos.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportați jurnalele din ultimele 5 minute.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Экспорт логов за последние 5 минут.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportujte záznamy za posledných 5 minút.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Извези евиденције за последњих 5 минута.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exportera loggarna från de senaste 5 minuterna.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Son 5 dakikanın loglarını dışa aktar.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Експортувати логи за останні 5 хвилин.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Xuất nhật ký trong 5 phút vừa rồi.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"导出最近 5 分钟的日志。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"匯出最近 5 分鐘的記錄。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"匯出最近 5 分鐘的記錄。\"\n          }\n        }\n      }\n    },\n    \"Failed to create GlobalEventTap: Accessibility permission not granted\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kon nie GlobalEventTap skep nie: Toeganklikheidtoestemming nie toegestaan nie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فشل في إنشاء GlobalEventTap: لم يتم منح إذن الوصول.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Greška u kreiranju GlobalEventTap: Dozvola za Pristupačnost nije odobrena\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No s'ha pogut crear GlobalEventTap: permís d'accessibilitat no concedit\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodařilo se vytvořit GlobalEventTap: Přístupnost není povolena\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke oprette GlobalEventTap: Tilgængelighedstilladelse ikke givet\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTap konnte nicht erstellt werden: Bedienungshilfen-Berechtigung nicht erteilt\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αποτυχία δημιουργίας GlobalEventTap: Η άδεια προσβασιμότητας δεν έχει παραχωρηθεί\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Error al crear GlobalEventTap: Permiso de accesibilidad no concedido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTapin luominen epäonnistui: Esteettömyyskäyttöoikeutta ei myönnetty\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Échec de la création de GlobalEventTap : autorisation d’accessibilité non accordée\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"יצירת GlobalEventTap נכשלה: הרשאת נגישות לא הוענקה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nem sikerült létrehozni a GlobalEventTap-et: Hozzáférhetőségi engedély nem lett megadva\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gagal membuat GlobalEventTap: Izin Aksesibilitas tidak diberikan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile creare GlobalEventTap: autorizzazione accessibilità non concessa\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTapの作成に失敗しました: アクセシビリティの許可が得られませんでした\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTap 생성 실패: 손쉬운 사용 권한 없음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTap ကို ဖန်တီးရန် ပျက်ကွက်သည်- Accessibility ခွင့်ပြုချက် မရရှိပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke opprette GlobalEventTap: Tilgjengelighets-tillatelse ikke gitt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTap kon niet worden gemaakt: Toegankelijkheidspermissie niet verleend\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie udało się utworzyć GlobalEventTap: nie przyznano uprawnień dostępności\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao criar GlobalEventTap: permissão de Acessibilidade não concedida\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao criar GlobalEventTap: permissão de Acessibilidade não concedida\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eroare la crearea GlobalEventTap: permisiunea de accesibilitate nu a fost acordată\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не удалось создать GlobalEventTap: разрешение на доступность не предоставлено\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodarilo sa vytvoriť GlobalEventTap: povolenie prístupnosti nebolo udelené\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Није успело стварање GlobalEventTap: Дозвола за приступачност није дата\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunde inte skapa GlobalEventTap: Tillgänglighetsbehörighet ej beviljad\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"GlobalEventTap oluşturulamadı: Erişilebilirlik izni verilmedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не вдалося створити GlobalEventTap: дозвіл на доступність не надано\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không thể tạo GlobalEventTap: Quyền trợ năng chưa được cấp\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"创建 GlobalEventTap 失败：未授予辅助权限\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法建立 GlobalEventTap：未授權輔助使用權限\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法建立 GlobalEventTap：未授予輔助功能權限\"\n          }\n        }\n      }\n    },\n    \"Failed to load the configuration: %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kon nie die konfigurasie laai nie: %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فشل في تحميل الإعدادات: %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Greška prilikom učitavanja konfiguracije: %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No s'ha pogut carregar la configuració: %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodařilo se načíst konfiguraci: %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke indlæse konfigurationen: %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration konnte nicht geladen werden: %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αποτυχία φόρτωσης της διαμόρφωσης: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No se pudo cargar la configuración: %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määrityksen lataaminen epäonnistui: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Échec du chargement de la configuration : %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"טעינת התצורה נכשלה: %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nem sikerült betölteni a konfigurációt: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gagal memuat konfigurasi: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile caricare la configurazione: %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定の読み込みに失敗しました: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 불러오기 실패: %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration ကို load လုပ်ရန် ပျက်ကွက်သည်- %@\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke laste konfigurasjonen: %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie kon niet worden geladen: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie udało się załadować konfiguracji: %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao carregar a configuração: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao carregar a configuração: %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eroare la încărcarea configurației: %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не удалось загрузить конфигурацию: %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodarilo sa načítať konfiguráciu: %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Није успело учитавање конфигурације: %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunde inte läsa in konfigurationen: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırma yüklenemedi: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не вдалося завантажити конфігурацію: %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không thể tải cấu hình: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加载配置失败： %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法載入設定：%@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法載入設定：%@\"\n          }\n        }\n      }\n    },\n    \"Failed to reload configuration\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kon nie konfigurasie herlaai nie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فشل في إعادة تحميل الإعدادات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Greška prilikom osvježavanja konfiguracije\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No s'ha pogut tornar a carregar la configuració\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodařilo se znovu načíst konfiguraci\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke genindlæse konfiguration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration konnte nicht neu geladen werden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αποτυχία επαναφόρτωσης της διαμόρφωσης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Error al recargar la configuración\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määrityksen uudelleenlataus epäonnistui\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Échec du rechargement de la configuration\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"טעינה מחדש של התצורה נכשלה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nem sikerült újra betölteni a konfigurációt\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gagal memuat ulang konfigurasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile ricaricare la configurazione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定の再読み込みに失敗しました\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 새로고침 실패\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration ကို reload လုပ်ရန် ပျက်ကွက်သည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke laste inn konfigurasjonen på nytt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie kon niet opnieuw worden geladen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie udało się ponownie załadować konfiguracji\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao recarregar a configuração\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao recarregar a configuração\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eroare la reîncărcarea configurației\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не удалось перезагрузить конфигурацию\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodarilo sa znova načítať konfiguráciu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Није успело поновно учитавање конфигурације\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunde inte läsa in konfigurationen igen\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırma yeniden yüklenemedi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не вдалося перезавантажити конфігурацію\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không thể tải lại cấu hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"加载配置失败\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法重新載入設定\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法重新載入設定\"\n          }\n        }\n      }\n    },\n    \"Failed to save the configuration: %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kon nie die konfigurasie stoor nie: %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فشل في حفظ الإعدادات: %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Greška prilikom spašavanja konfiguracije: %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No s'ha pogut desar la configuració: %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodařilo se uložit konfiguraci: %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke gemme konfigurationen: %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguration konnte nicht gespeichert werden: %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αποτυχία αποθήκευσης της διαμόρφωσης: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No se pudo guardar la configuración: %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määrityksen tallentaminen epäonnistui: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Échec de l’enregistrement de la configuration : %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שמירת התצורה נכשלה: %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nem sikerült menteni a konfigurációt: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gagal menyimpan konfigurasi: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impossibile salvare la configurazione: %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定の保存に失敗しました: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 저장 실패: %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuration ကို သိမ်းဆည်းရန် ပျက်ကွက်သည်- %@\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunne ikke lagre konfigurasjonen: %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie kon niet worden opgeslagen: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie udało się zapisać konfiguracji: %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao salvar a configuração: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falha ao salvar a configuração: %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eroare la salvarea configurației: %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не удалось сохранить конфигурацию: %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodarilo sa uložiť konfiguráciu: %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Није успело чување конфигурације: %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunde inte spara konfigurationen: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırma kaydedilemedi: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не вдалося зберегти конфігурацію: %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không thể lưu cấu hình: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"保存配置失败： %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法儲存設定：%@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無法儲存設定：%@\"\n          }\n        }\n      }\n    },\n    \"Fast\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vinnig\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سريع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ràpid\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychle\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hurtig\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schnell\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γρήγορη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rápido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nopea\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rapide\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מהיר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gyors\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cepat\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veloce\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"速い\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"빠르게\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မြန်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rask\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snel\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szybko\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rápido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rápido\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rapid\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Быстро\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Брзо\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snabb\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hızlı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидко\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhanh\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快\"\n          }\n        }\n      }\n    },\n    \"Fast cubic pickup that settles into a shorter tail.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vinnige kubiese aanvang wat in 'n korter uitloop bedaar.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انطلاقة تكعيبية سريعة تستقر في ذيل أقصر.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brz kubični početak koji se smiri u kraći završetak.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arrencada cúbica ràpida que es resol en una cua més curta.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlý kubický nástup, který přechází do kratšího dozvuku.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hurtig kubisk start, der falder til ro i en kortere hale.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schneller kubischer Beginn, der in einen kürzeren Nachlauf übergeht.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γρήγορο κυβικό ξεκίνημα που καταλήγει σε πιο σύντομη ουρά.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arranque cúbico rápido que se asienta en una cola más corta.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nopea kuutiollinen aloitus, joka asettuu lyhyempään häntään.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Départ cubique rapide qui se stabilise sur une traîne plus courte.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה קובייתית מהירה שמתייצבת לזנב קצר יותר.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gyors köbös indulás, amely rövidebb lecsengésbe simul.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Awalan kubik yang cepat dan berakhir pada ekor yang lebih pendek.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avvio cubico rapido che si assesta in una coda più corta.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立ち上がりの速いキュービックで、短めの余韻に落ち着きます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"빠르게 치고 나가는 큐빅 반응이 더 짧은 꼬리로 정리됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမြန် cubic စတင်မှုက ပိုတိုသော အဆုံးပိုင်းသို့ တည်ငြိမ်သွားသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rask kubisk respons som roer seg i en kortere hale.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snelle kubische oppak die overgaat in een kortere uitloop.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szybkie sześcienne wejście, które przechodzi w krótszy ogon.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arranque cúbico rápido que assenta numa cauda mais curta.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arranque cúbico rápido que se acomoda em uma cauda mais curta.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pornire cubică rapidă, care se așază într-o coadă mai scurtă.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Быстрый кубический старт, переходящий в более короткий хвост.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchly kubický nástup, ktorý prejde do kratšieho dozvuku.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Брз кубни почетак који се смирује у краћи реп.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snabb kubisk uppbyggnad som landar i en kortare svans.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daha kısa bir kuyruğa oturan hızlı kübik başlangıç.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкий кубічний старт, що переходить у коротший хвіст.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khởi đầu bậc ba nhanh, rồi ổn định với phần đuôi ngắn hơn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次曲线起步很快，随后收束为更短的尾段。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次曲線起步很快，隨後收束為更短的尾段。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"三次曲線起步很快，隨後收束為更短的尾段。\"\n          }\n        }\n      }\n    },\n    \"Fast forward\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vinnig vorentoe\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تقديم سريع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzaj\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avançament ràpid\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přetočit vpřed\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spol frem\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorspulen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γρήγορη προώθηση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avance rápido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nopeuta eteenpäin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avance rapide\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הרץ קדימה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gyors előre\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maju cepat\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanzamento rapido\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"早送り\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"앞으로 빨리감기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ရှေ့သို့ရစ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spol fremover\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vooruitspoelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń do przodu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanço rápido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanço rápido\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avans rapid\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемотка вперед\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchly posun vpred\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Убрзано напред\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snabbspola framåt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İleri sar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемотати вперед\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tua đi\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快进\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快轉\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快轉\"\n          }\n        }\n      }\n    },\n    \"Fast initial response that settles quickly.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vinnige aanvanklike reaksie wat vinnig tot rus kom.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"استجابة أولية سريعة تستقر بسرعة.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brz početni odgovor koji se brzo smiri.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resposta inicial ràpida que s'estabilitza de seguida.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlá počáteční odezva, která se rychle ustálí.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hurtig første respons, der hurtigt falder til ro.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schnelle Anfangsreaktion, die sich rasch beruhigt.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γρήγορη αρχική απόκριση που σταθεροποιείται γρήγορα.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Respuesta inicial rápida que se estabiliza enseguida.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nopea alkuvaste, joka rauhoittuu nopeasti.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Réponse initiale rapide qui se stabilise vite.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תגובה התחלתית מהירה שמתייצבת במהירות.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gyors kezdeti reakció, amely hamar megnyugszik.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Respons awal yang cepat dan segera stabil.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Risposta iniziale rapida che si assesta velocemente.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立ち上がりが速く、すぐに落ち着きます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"초기 반응이 빠르고 금방 안정됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အစပိုင်း တုံ့ပြန်မှု မြန်ပြီး မကြာခင် တည်ငြိမ်သွားသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rask første respons som roer seg raskt.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snelle eerste reactie die zich snel stabiliseert.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Szybka reakcja początkowa, która szybko się stabilizuje.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resposta inicial rápida que estabiliza depressa.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resposta inicial rápida que se estabiliza rapidamente.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Răspuns inițial rapid, care se stabilizează repede.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Быстрый начальный отклик, который быстро успокаивается.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchla počiatočná odozva, ktorá sa rýchlo ustáli.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Брз почетни одзив који се брзо смирује.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snabb initial respons som snabbt lugnar sig.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hızlı ilk tepki, kısa sürede dengelenir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкий початковий відгук, що швидко стабілізується.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phản hồi ban đầu nhanh, rồi nhanh chóng ổn định.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"初始响应很快，并会迅速稳定下来。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"初始回應很快，並會迅速穩定下來。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"初始回應很快，並會迅速穩定下來。\"\n          }\n        }\n      }\n    },\n    \"Feature request\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gaan-na-funksie versoek\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"طلب مِيزة غير موجودة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zatraži mogućnost\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Petició de funció\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Žádost o novou funkci\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ændringsønske\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verbesserungen vorschlagen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αιτήματα προσθήκης νέας λειτουργίας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Solicitud de funcionalidad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ominaisuuspyyntö\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Demande de fonctionnalité\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בקשת אפשרות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Funkció kérés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Permintaan fitur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Richiesta di funzionalità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"機能の提案\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"피드백 보내기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လုပ်ဆောင်ချက်အသစ်များ တောင်းခံရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Funksjonsforespørsel\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Functie voorstellen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sugestie funkcji\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Solicitação de recurso\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fazer uma sugestão\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Solicitați o caracteristică\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Предложить новую функцию\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Požiadavka na funkciu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Захтев за функцију\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Funktionsförfrågan\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İyileştirme önerin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запропонувати фунцкію\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yêu cầu tính năng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"功能建议\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"功能建議\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"功能建議\"\n          }\n        }\n      }\n    },\n    \"Flat\" : {\n      \"comment\" : \"Preset label for scroll curve. Means flatter acceleration with less curvature.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plat\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مسطح\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ravno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pla\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plochá\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flad\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flach\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επίπεδο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plano\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tasainen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plat\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שטוח\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lapos\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Datar\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Piatto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"フラット\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"낮음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညီညာသော\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flat\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vlak\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Płaski\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plano\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plano\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плоская\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plochá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Раван\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Platt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Düz\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавно\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phẳng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平坦\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平面\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑\"\n          }\n        }\n      }\n    },\n    \"Forward\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorentoe\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إلى الأمام\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naprijed\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Endavant\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vpřed\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Frem\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vor\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μπροστά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Adelante\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eteenpäin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivant\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קדימה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Előre\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maju\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avanti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"進む\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"앞으로 가기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အရှေ့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fremover\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Heen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Do przodu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avançar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avançar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Înainte\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вперёд\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vpred\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Напред\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Framåt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İleri\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Уперед\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuyển tiếp\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前进\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前進\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前進\"\n          }\n        }\n      }\n    },\n    \"Forward button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorentoe-knoppie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"زر إلى الأمام\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dugme za naprijed\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botó endavant\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačítko vpřed\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fremad-knap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vor-Taste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κουμπί προώθησης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botón adelante\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eteenpäin-painike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bouton Avant\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחצן קדימה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Előre gomb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol maju\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsante Avanti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"進むボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"앞으로 가기 버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ရှေ့သို့ ပြောင်းသော ခလုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fremover-knapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vooruit-knop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przycisk do przodu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão Avançar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão Avançar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buton înainte\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопка Вперёд\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačidlo Ďalej\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дугме напред\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Framåtknapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İleri tuşu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопка «Вперед»\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút Tiến\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前进键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前進鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前進鍵\"\n          }\n        }\n      }\n    },\n    \"General\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Algemeen\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عام\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Generalno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"General\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obecné\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Generelt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Allgemein\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γενικά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"General\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yleiset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Général\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כללי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Általános\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Umum\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Generale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"一般\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"일반\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အထွေထွေ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Generelt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Algemeen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogólne\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geral\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geral\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"General\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Основные\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Všeobecné\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Опште\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Allmänt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Genel\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Загальні\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cài đặt chung\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"通用\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"通用\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"通用\"\n          }\n        }\n      }\n    },\n    \"Gesture Actions\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebare-aksies\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إجراءات الإيماءات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Radnje gestama\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accions de gestos\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akce gesta\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gestushandlinger\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gestenaktionen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενέργειες χειρονομιών\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acciones de gestos\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eletoiminnot\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actions de geste\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"פעולות מחוות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Érintés műveletek\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tindakan Gestur\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Azioni gesto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ジェスチャーアクション\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"제스처 동작\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမူအယာ လုပ်ဆောင်ချက်များ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gesthandlinger\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebarenacties\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akcje gestów\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ações de Gesto\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ações de Gesto\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acțiuni gestuale\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Действия жестов\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akcie gest\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Акције покрета\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geståtgärder\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hareket Eylemleri\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дії жестів\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hành động Cử chỉ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"手势操作\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"手勢動作\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"手勢操作\"\n          }\n        }\n      }\n    },\n    \"Get more help\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kry meer hulp\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"المزيد من المساعدة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zatraži dodatnu pomoć\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obtén més ajuda\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Více informací\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Få mere hjælp\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weitere Hilfe erhalten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Λάβετε περισσότερη βοήθεια\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obtener más ayuda\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hanki lisäohjeita\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obtenir plus d'aide\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קבל עזרה נוספת\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"További segítség\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dapatkan bantuan lebih lanjut\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ricevi ulteriore supporto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ヘルプ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"도움이 필요하신가요?\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အကူအညီ ပိုမိုရယူရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Få mer hjelp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Meer hulp\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uzyskaj więcej pomocy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obter mais ajuda\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obter mais ajuda\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obțineți mai mult ajutor\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Получить помощь\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Získať ďalšiu pomoc\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додатна помоћ\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Få mer hjälp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daha fazla yardım\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Додаткова допомога\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhận trợ giúp\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"获得更多帮助\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"獲取更多幫助\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"獲取更多幫助\"\n          }\n        }\n      }\n    },\n    \"Hold keys while pressed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hou sleutels in tydens druk\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إبقاء المفاتيح مضغوطة أثناء الضغط\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Drži tipke dok je pritisnut\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén les tecles premudes\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Držet klávesy stisknuté\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold tasterne nede\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tasten gedrückt halten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κράτημα πλήκτρων όσο πατιέται\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantener teclas mientras se pulsa\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pidä näppäimet painettuna\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maintenir les touches enfoncées\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החזק מקשים בעת לחיצה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Billentyűk lenyomva tartása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tahan tombol saat ditekan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tieni premuti i tasti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"押している間キーを保持\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"누르고 있는 동안 키 유지\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖိထားစဉ် ကီးများကို ဖိထားရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold tastene nede\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Houd toetsen ingedrukt\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trzymaj klawisze wciśnięte\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Manter teclas premidas\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Manter teclas pressionadas\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menține tastele apăsate\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удерживать клавиши при нажатии\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Držať klávesy stlačené\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Држи тастере док је притиснут\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Håll tangenter intryckta\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tuşları basılı tut\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Утримувати клавіші при натисканні\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giữ phím khi nhấn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住时保持按下\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住時維持按下\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住時維持按下\"\n          }\n        }\n      }\n    },\n    \"Hold the button and drag to trigger gestures. Drag at least %lld pixels in one direction.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hou die knoppie vas en sleep om gebare te aktiveer. Sleep ten minste %lld pixels in een rigting.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اضغط مع الاستمرار على الزر واسحب لتشغيل الإيماءات. اسحب %lld بكسل على الأقل في اتجاه واحد.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Držite dugme i prevucite da biste pokrenuli geste. Prevucite najmanje %lld piksela u jednom smjeru.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén premut el botó i arrossega per activar gestos. Arrossega almenys %lld píxels en una direcció.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržte tlačítko a přetáhněte pro spuštění gest. Přetáhněte alespoň %lld pixelů jedním směrem.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold knappen nede og træk for at udløse gestus. Træk mindst %lld pixels i én retning.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Halten Sie die Schaltfläche gedrückt und ziehen Sie, um Gesten auszulösen. Ziehen Sie mindestens %lld Pixel in eine Richtung.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κρατήστε πατημένο το κουμπί και σύρετε για να ενεργοποιήσετε χειρονομίες. Σύρετε τουλάχιστον %lld pixel προς μία κατεύθυνση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén pulsado el botón y arrastra para producir gestos. Arrastra al menos %lld píxeles en una dirección.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pidä painiketta painettuna ja vedä eleiden käynnistämiseksi. Vedä vähintään %lld pikseliä yhteen suuntaan.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maintenez le bouton enfoncé et faites glisser pour déclencher des gestes. Faites glisser sur au moins %lld pixels dans une direction.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החזק את הלחצן וגרור כדי להפעיל מחוות. גרור לפחות %lld פיקסלים בכיוון אחד.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tartsa lenyomva a gombot, és húzza az érintés aktiválásához. Húzza legalább %lld képpont távolságra egy irányban.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tahan tombol dan seret untuk memicu gestur. Seret setidaknya %lld piksel ke satu arah.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tieni premuto il pulsante e trascina per attivare i gesti. Trascina almeno %lld pixel in una direzione.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ボタンを押したままドラッグしてジェスチャーをトリガーします。いずれかの方向に少なくとも%lldピクセルドラッグしてください。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버튼을 누른 상태에서 드래그하여 제스처를 트리거합니다. 한 방향으로 최소 %lld 픽셀을 드래그하세요.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမူအယာများကို trigger လုပ်ရန် ခလုတ်ကို ကိုင်ပြီး ဆွဲပါ။ တစ်ဖက်သို့ အနည်းဆုံး %lld pixels ဆွဲပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold knappen inne og dra for å utløse gester. Dra minst %lld piksler i én retning.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Houd de knop ingedrukt en sleep om gebaren te activeren. Sleep minstens %lld pixels in één richting.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przytrzymaj przycisk i przeciągnij, aby wywołać gesty. Przeciągnij co najmniej %lld pikseli w jednym kierunku.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantenha o botão pressionado e arraste para acionar gestos. Arraste pelo menos %lld pixels em uma direção.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantenha o botão pressionado e arraste para acionar gestos. Arraste pelo menos %lld pixels em uma direção.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ține apăsat butonul și trage pentru a declanșa gesturi. Trage cel puțin %lld pixeli într-o direcție.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удерживайте кнопку и перетаскивайте, чтобы активировать жесты. Перетащите не менее %lld пикселей в одном направлении.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržte tlačidlo a potiahnite, aby ste spustili gestá. Potiahnite aspoň %lld pixelov jedným smerom.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Држите дугме и превуците да бисте покренули покрете. Превуците најмање %lld пиксела у једном смеру.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Håll ned knappen och dra för att aktivera gester. Dra minst %lld pixlar i en riktning.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hareketleri tetiklemek için düğmeyi basılı tutun ve sürükleyin. Tek bir yönde en az %lld piksel sürükleyin.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Утримуйте кнопку та перетягніть, щоб викликати жести. Перетягніть щонайменше на %lld пікселів в одному напрямку.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giữ nút và kéo để kích hoạt cử chỉ. Kéo ít nhất %lld pixel theo một hướng.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住按钮并拖动以触发手势。沿一个方向拖动至少 %lld 像素。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住按鈕並拖曳以觸發手勢。朝任一方向拖曳至少 %lld 個像素。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住按鈕並拖曳以觸發手勢。朝一個方向拖曳至少 %lld 個像素。\"\n          }\n        }\n      }\n    },\n    \"Hold the trigger while moving to scroll, then release it to stop.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hou die sneller vas terwyl jy beweeg om te blaai, en laat dit dan los om te stop.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اضغط مع الاستمرار على المشغل أثناء التحريك للتمرير، ثم حرره للتوقف.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Držite okidač tokom pomicanja za skrolovanje, zatim ga otpustite za zaustavljanje.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén premut el disparador mentre et mous per desplaçar-te, després deixa'l anar per aturar-te.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržte spoušť při pohybu pro rolování, poté ji uvolněte pro zastavení.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold udløseren nede, mens du bevæger dig for at rulle, og slip den derefter for at stoppe.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Halten Sie den Auslöser gedrückt, während Sie sich bewegen, um zu scrollen, und lassen Sie ihn dann los, um zu stoppen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κρατήστε πατημένο το κουμπί ενεργοποίησης κατά τη μετακίνηση για κύλιση, και μετά αφήστε το για να σταματήσετε.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén presionado el gatillo mientras te mueves para desplazarte, luego suéltalo para detenerte.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pidä liipaisinta painettuna vierittäessäsi, vapauta se pysäyttääksesi.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maintenez la gâchette enfoncée pendant le déplacement pour faire défiler, puis relâchez-la pour arrêter.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החזק את ההדק תוך כדי תנועה כדי לגלול, ואז שחרר אותו כדי לעצור.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tartsa lenyomva a kioldót mozgás közben a görgetéshez, majd engedje fel a leállításhoz.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tahan pemicu sambil bergerak untuk menggulir, lalu lepaskan untuk berhenti.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tieni premuto il grilletto mentre ti muovi per scorrere, quindi rilascialo per fermarti.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"トリガーを押したまま移動するとスクロールし、離すと停止します。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이동 중에 트리거를 누르고 있으면 스크롤되고, 놓으면 멈춥니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll လုပ်ရန် ရွှေ့နေစဉ် trigger ကို ကိုင်ထားပါ၊ ထို့နောက် ရပ်တန့်ရန် လွှတ်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold utløseren inne mens du beveger deg for å rulle, slipp deretter for å stoppe.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Houd de trigger ingedrukt tijdens het bewegen om te scrollen, laat deze dan los om te stoppen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przytrzymaj wyzwalacz podczas ruchu, aby przewijać, a następnie puść go, aby zatrzymać.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantenha o gatilho pressionado enquanto se move para rolar e, em seguida, solte-o para parar.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantenha o gatilho pressionado enquanto se move para rolar e solte-o para parar.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ține declanșatorul în timp ce te deplasezi pentru a derula, apoi eliberează-l pentru a opri.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удерживайте триггер во время движения для прокрутки, затем отпустите его, чтобы остановить.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržte spúšť pri pohybe na rolovanie, potom ho uvoľnite na zastavenie.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Држите окидач док се крећете да бисте скроловали, а затим га отпустите да бисте зауставили.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Håll ned utlösaren medan du flyttar för att rulla, släpp sedan för att stoppa.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırmak için hareket ederken tetiği basılı tutun, ardından durdurmak için bırakın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Утримуйте тригер під час руху для прокручування, потім відпустіть, щоб зупинити.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giữ cò khi di chuyển để cuộn, sau đó nhả ra để dừng.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"移动时按住触发器进行滚动，然后释放它以停止。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"移動時按住觸發器即可捲動，放開即可停止。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"移動時按住觸發器進行捲動，然後放開以停止。\"\n          }\n        }\n      }\n    },\n    \"Hold to scroll\" : {\n      \"comment\" : \"Autoscroll mode label. The trigger must stay held down while moving to scroll.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hou om te blaai\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اضغط للتمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Držite za pomicanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén premut per desplaçar-te\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržet pro rolování\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold for at rulle\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zum Scrollen gedrückt halten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κράτημα για κύλιση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantener para desplazarse\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pidä vierittääksesi\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maintenir pour faire défiler\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החזק כדי לגלול\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tartás a görgetéshez\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tahan untuk menggulir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tieni premuto per scorrere\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"長押しでスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"누르고 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll လုပ်ရန် ကိုင်ထားပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hold inne for å rulle\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingedrukt houden om te scrollen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przytrzymaj, aby przewijać\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Manter para rolar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Manter para rolar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ține pentru a derula\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Удерживать для прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržať na rolovanie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Држи за скроловање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Håll för att rulla\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırmak için basılı tut\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Утримувати для прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giữ để cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住以滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住以捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住捲動\"\n          }\n        }\n      }\n    },\n    \"Homepage\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tuisblad\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الصفحة الرئيسية\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Početna\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pàgina d'inici\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stránky aplikace\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hjemmeside\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Homepage\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αρχική σελίδα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Página web\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kotisivu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Page d'accueil\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"דף הבית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kezdőlap\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beranda\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Home page\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ホームページ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"홈페이지\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပင်မစာမျက်နှာ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hjemmeside\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Homepage\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Strona WWW\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Página inicial\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Página inicial\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pagina de pornire\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Домашняя страница\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Domovská stránka\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Почетна страница\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hemsida\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anasayfa\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Домашня сторінка\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trang chủ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"主页\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"首頁\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"首頁\"\n          }\n        }\n      }\n    },\n    \"Horizontal\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horisontaal\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"أُفقي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontalno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horitzontal\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontální\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horisontal\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Οριζόντια\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vaakasuunta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אופקי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vízszintes\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Orizzontale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"横方向\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"수평 방향\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလျားလိုက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horisontal\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontaal\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poziomo\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontal\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Orizontal\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Горизонтальная\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horizontálne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Хоризонтално\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Horisontal\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yatay\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Горизонтальне\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn ngang\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"横向\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"橫向\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"橫向\"\n          }\n        }\n      }\n    },\n    \"If enabled, %@ will not modify events sent by other applications, such as Logi Options+.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indien geaktiveer, sal %@ nie gebeurtenisse wat deur ander toepassings gestuur word, soos Logi Options+, wysig nie.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إذا تم تمكين هذا الخيار، فلن يقوم %@ بتعديل الأحداث المرسلة من تطبيقات أخرى، مثل Logi Options+.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ako je omogućeno, %@ neće mijenjati događaje koje šalju druge aplikacije, kao npr. Logi Options+.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Si s'habilita, %@ no modificarà els esdeveniments enviats per altres aplicacions, com ara Logi Options+.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po zapnutí nebude %@ upravovat události poslané ostatními aplikacemi jako je Logi Options+.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hvis aktiveret, vil %@ ikke ændre begivenheder sendt af andre programmer, såsom Logi Options+.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wenn aktiviert, verändert %@ keine Ereignisse, die von anderen Anwendungen, wie z. B. Logi Options+, gesendet werden.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αν ενεργοποιηθεί, το %@ δε θα τροποποιήσει τα συμβάντα που αποστέλλονται από άλλες εφαρμογές, όπως το Logi Options+.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Si está activado, %@ no modificará los eventos enviados por otras aplicaciones, tales como Logi Options+.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jos tämä on käytössä, %@ ei muokkaa muiden sovellusten, kuten Logi Options+:n, lähettämiä tapahtumia.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Si activé, %@ ne modifiera pas les événements envoyés par d'autres applications, telles que Logi Options+.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אם פועל, %@ לא ישנה אירועים שנשלחים מאפליקציות אחרות, כמו Logi Options+.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ha engedélyezve van, a(z) %@ nem módosítja más alkalmazások által küldött eseményeket, például a Logi Options+-t.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jika diaktifkan, %@ tidak akan mengubah peristiwa yang dikirim oleh aplikasi lain, seperti Logi Options+.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se abilitato, %@ non modificherà gli eventi inviati da altre applicazioni, come Logi Options+.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"有効にすると、 %@ はLogi Options+などの他のアプリケーションから送信されたイベントを変更しません。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"활성화되면, %@는 Logi Options+와 같은 다른 응용 프로그램에서 보낸 이벤트를 수정하지 않습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အသုံးပြုခွင့်ပေးထားလျှင်၊ %@ သည် Logi Options+ ကဲ့သို့သော အက်ပ်ပလီကေးရှင်းများမှ လုပ်ဆောင်ချက်များကို အသုံးမပြုပါ။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hvis aktivert, vil %@ ikke endre hendelser sendt av andre programmer, slik som Logi Options+.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indien ingeschakeld, zal %@ instellingen die door andere applicaties worden beheerd, zoals Logi Options+, niet wijzigen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jeżeli włączone, %@ nie będzie modyfikował zdarzeń wysłanych przez inne aplikacje, takich jak Logi Options+.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se ativado, %@ não modificará eventos enviados por outros aplicativos, como Logi Options+.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se habilitado, %@ não irá modificar eventos enviados por outras aplicações, como Logi Options+.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dacă este activat, %@ nu va modifica evenimentele trimise de alte aplicații, cum ar fi Logi Options+.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Если включено, %@ не будет изменять события, отправленные другими приложениями, такими как Logi Options+.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po zapnutí %@ nebude upravovať udalosti odoslané inými aplikáciami, ako napr. Logi Options+.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ако је омогућено, %@ неће мењати догађаје послате од стране других апликација, као што је Logi Options+.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Om aktiverat kommer %@ inte att ändra händelser som skickas av andra program, som Logi Options+.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etkinleştirilirse, %@, Logi Options+ gibi diğer uygulamalar tarafından gönderilen olayları değiştirmeyecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Якщо увімкнено, %@ не змінюватиме події, надіслані іншими застосунками, такими як Logi Options+.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khi bật, %@ sẽ không sửa đổi các sự kiện được gửi bởi ứng dụng khác, chẳng hạn như Logi Options+.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"如果启用， %@ 将不会修改其他应用程序发送的事件，如 Logi Options+。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"如果啟用， %@ 將不會修改其他應用程式發送的事件，如 Logi Options+。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"如果啟用， %@ 將不會修改其他應用程式發送的事件，如 Logi Options+。\"\n          }\n        }\n      }\n    },\n    \"If you are reporting a bug, it would be helpful to attach the logs.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As jy 'n fout rapporteer, sal dit nuttig wees om die logs aan te heg.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إذا كنت تبلغ عن خطأ، فسيكون من المفيد إرفاق السجلات.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ako prijavljujete grešku, bilo bi nam korisno da priložite logove.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Si estàs informant d'un error, seria útil adjuntar els registres.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokud nahlašujete chybu, bylo by užitečné přiložit protokoly.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hvis du rapporterer en fejl, er det være nyttigt at vedhæfte logfilerne.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wenn Sie einen Fehler melden, wäre es hilfreich, die Logdateien anzuhängen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εάν αναφέρετε ένα σφάλμα, θα ήταν χρήσιμο να επισυνάψετε τα αρχεία καταγραφής.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Si está informando de un error, sería útil adjuntar los registros.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jos raportoit virheestä, lokien liittäminen olisi hyödyllistä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Si vous signalez un bug, il serait utile de joindre les journaux.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אם את\\\\ה מדווח\\\\ת על באג, זה יכול לעזור לצרף את הלוגים.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ha hibát jelent, hasznos lenne csatolni a naplókat.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jika Anda melaporkan bug, akan sangat membantu untuk melampirkan log.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se stai segnalando un bug, sarebbe utile allegare i registri.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"バグを報告する場合、ログを添付して頂けると助かります。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버그를 보고하는 경우 로그를 첨부하면 도움이 됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"သင်သည် ချို့ယွင်းချက်တစ်ခုကို report လုပ်မည့်အခါ မှတ်တမ်းများကို ပူးတွဲ၍ တင်ပါက အထောက်အကူပြုမည်ဖြစ်သည်။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hvis du rapporterer en feil, kan det være nyttig å legge ved loggene.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Als je een bug vindt, ontvangen we ook graag een logbestand.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jeżeli zgłaszasz błąd, pomocne byłoby załączenie logów.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se você estiver relatando um bug, seria útil anexar os registros.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se você estiver reportando um bug, seria muito útil anexar os registros de eventos.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dacă raportezi o eroare, ar fi util să atașezi jurnalele.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Если вы сообщаете об ошибке, пожалуйста, прикрепляйте логи.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ak nahlasujete chybu, bolo by užitočné priložiť záznamy.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ако пријављујете грешку, било би корисно приложити евиденције.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Om du rapporterar ett fel skulle det vara bra att bifoga loggarna.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bir hatayı bildiriyorsanız, logları eklemeniz yararlı olacaktır.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Якщо ви повідомляєте про помилку, було б корисно прикріпити файл журналу.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nếu bạn muốn báo lỗi, sẽ tốt hơn nếu bạn đính kèm tệp nhật ký.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"如果你要报告 bug，附上日志会很有帮助。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"如果你要回報 bug，附上記錄會很有幫助。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"如果你要報告 bug，附上記錄會很有幫助。\"\n          }\n        }\n      }\n    },\n    \"Ignore modifier\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoreer wysiger\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تجاهل المعدّل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoriraj modifikator\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora el modificador\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorovat modifikátor\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer modifikationstast\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sondertaste ignorieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αγνόηση μεταβλητής\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignore modifier\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar modificador\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ohita muokkain\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer le modificateur\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התעלם ממקש\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Módosító figyelmen kívül hagyása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abaikan pengubah\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora il modificatore\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"修飾キーを無視\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"보조 키 무시\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifier ခလုတ်များ ကို လျစ်လျူရှုရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer modifikasjonstast\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanpassing negeren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoruj modyfikator\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar modificador\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar modificador\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoră modificatorul\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Игнорировать модификатор\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorovať modifikátor\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Игнориши модификатор\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorera modifierare\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nitelemeyi yok say\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ігнорувати модифікатор\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bỏ qua phím bổ trợ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略修饰键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略變更鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略變更鍵\"\n          }\n        }\n      }\n    },\n    \"Ignore rapid clicks within a certain time period.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoreer vinnige klikke binne 'n sekere tydperk.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تجاهل النقرات السريعة خلال فترة زمنية معينة.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoriraj brze klikove unutar određenog vremenskog perioda.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora els clics ràpids dins d'un determinat període de temps.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoruje rychlá kliknutí v určité časové době.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer hurtige klik inden for et bestemt tidsrum.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schnelle, aufeinanderfolgende Klicks innerhalb einer bestimmten Zeitspanne ignorieren.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Παράβλεψη γρήγορων κλικ μέσα σε ένα ορισμένο χρονικό διάστημα.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar pulsaciones rápidas dentro de un determinado período de tiempo.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ohita nopeat napsautukset tietyn ajanjakson sisällä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer les clics rapides dans une certaine période.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התעלם מלחיצות מהירות שמתרחשות בפרק זמן מסוים.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gyors kattintások figyelmen kívül hagyása egy bizonyos időn belül.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abaikan klik cepat dalam periode waktu tertentu.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora clic rapidi entro un certo periodo di tempo.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"一定時間内での素早いクリックを無視します。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"특정 시간 내의 빠른 클릭을 무시합니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အချိန်တစ်ခုအတွင်း ခဏခဏ နှိပ်ခြင်းကို ကန့်သန့်ရန်။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorer raske klikk innenfor en bestemt tidsperiode.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Negeer snelle klikken binnen een bepaalde periode.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoruj szybkie kliknięcia w określonym czasie.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorar cliques rápidos dentro de um período determinado.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignora cliques rápidos dentro de um período determinado.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignoră clicurile rapide într-o anumită perioadă de timp.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пропускает частые нажатие клавиш.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorovať rýchle kliknutia v určitom časovom období.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Игнориши брзе кликове у одређеном временском периоду.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ignorera snabba klick inom en viss tidsperiod.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Belli bir süre içindeki hızlı tıklamaları yok say.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ігнорувати швидкі клацання протягом певного періоду часу.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bỏ qua các nhấp chuột nhanh chóng trong một khoảng thời gian nhất định.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略在特定时间段内的快速点击。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略在特定時間段內的快速點擊。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"忽略在特定時間段內的快速點擊。\"\n          }\n        }\n      }\n    },\n    \"Immediate\" : {\n      \"comment\" : \"Preset label for response or inertia. Means the scrolling reaction happens quickly with minimal delay.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onmiddellik\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فوري\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trenutno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Immediat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okamžitá\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Øjeblikkelig\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sofort\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Άμεσο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inmediato\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Välitön\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Immédiat\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מיידי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Azonnali\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Segera\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Immediato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"即時\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"즉시\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ချက်ချင်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Umiddelbar\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Direct\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Natychmiastowy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Imediato\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Imediato\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Imediat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Немедленно\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okamžitá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тренутно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omedelbar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anında\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Миттєво\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ngay lập tức\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立即\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立即\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"立即\"\n          }\n        }\n      }\n    },\n    \"Increase display brightness\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verhoog skermhelderheid\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"زيادة سطوع الشاشة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povećaj osvjetljenje ekrana\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Augmenta la brillantor de la pantalla\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zvýšit jas displeje\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forøg lysstyrke\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bildschirmhelligkeit erhöhen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αύξηση φωτεινότητας οθόνης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar brillo de pantalla\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lisää näytön kirkkautta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Augmenter la luminosité d'affichage\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגבר בהירות תצוגה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Képernyő fényerejének növelése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tingkatkan kecerahan layar\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumenta la luminosità dello schermo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ディスプレイの明るさを上げる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"화면 밝기 높이기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Screen အလင်း တိုးရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Øk skjermlysstyrke\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verhoog schermhelderheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zwiększ jasność wyświetlacza\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar brilho do monitor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar brilho da tela\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mărește luminozitatea ecranului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увеличить яркость экрана\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zvýšenie jasu displeja\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повећај осветљеност екрана\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öka skärmens ljusstyrka\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ekran parlaklığını arttır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Збільшити яскравість дисплея\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng độ sáng màn hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"提高显示器亮度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"增加顯示器亮度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"增加顯示器亮度\"\n          }\n        }\n      }\n    },\n    \"Increase keyboard brightness\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verhoog sleutelbordhelderheid\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"زيادة سطوع لوحة المفاتيح\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povećaj osvjetljenje tastature\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Augmenta la brillantor del teclat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zvýšit jas klávesnice\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forøg tastaturets lysstyrke\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastaturhelligkeit erhöhen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αύξηση φωτεινότητας πληκτρολογίου\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar el brillo del teclado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lisää näppäimistön kirkkautta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Augmenter la luminosité d'affichage\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגבר בהירות מקלדת\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Billentyűzet fényerejének növelése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tingkatkan kecerahan keyboard\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumenta la luminosità della tastiera\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ディスプレイの明るさを上げる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"키보드 밝기 높이기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ကီးဘုတ် အလင်း တိုးရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Øk tastaturlysstyrke\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toetsenbord helderheid verhogen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zwiększ jasność klawiatury\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar brilho do teclado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar brilho do teclado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mărește luminozitatea tastaturii\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увеличить яркость клавиатуры\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zvýšenie jasu klávesnice\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повећај осветљеност тастатуре\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öka tangentbordets ljusstyrka\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klavye parlaklığını arttır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Збільшити яскравість клавіатури\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng độ sáng bàn phím\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"提高键盘亮度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"增加鍵盤亮度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"增加鍵盤亮度\"\n          }\n        }\n      }\n    },\n    \"Increase volume\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verhoog volume\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"زيادة مستوى الصوت\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Povećaj glasnoću zvuka\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Puja el volum\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zvýšit hlasitost\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forøg lydstyrke\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lautstärke erhöhen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αύξηση έντασης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar volumen\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lisää äänenvoimakkuutta\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Augmenter le volume\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגבר את עוצמת הקול\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hangerő növelése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tingkatkan volume\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumenta il volume\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"音量を上げる\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"음량 높이기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အသံကျယ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Øk volum\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verhoog volume\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podgłośnij\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar volume\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aumentar volume\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mărește volumul\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Увеличить громкость\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zvýšiť hlasitosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повећај јачину звука\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öka volym\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ses seviyesini arttır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Збільшити гучність\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng âm lượng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"提高音量\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"增加音量\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"增加音量\"\n          }\n        }\n      }\n    },\n    \"Installed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geïnstalleer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مثبت\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instalirano\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instal·lat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nainstalováno\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Installerede\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Installiert\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εγκατεστημένες\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instalado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Asennettu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Installé\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מותקן\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Telepítve\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terpasang\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Installato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設置されているアプリ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설치됨\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ထည့်သွင်းပြီးသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Installert\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geïnstalleerd\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zainstalowane\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instalado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instalado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instalat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Установлены\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nainštalované\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Инсталирано\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Installerad\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurulu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Установлені\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đã cài đặt\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安装\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安裝\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已安裝\"\n          }\n        }\n      }\n    },\n    \"Invalid JSON: %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ongeldige JSON: %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON غير صالح: %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neispravan JSON: %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON no vàlid: %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neplatný JSON: %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugyldig JSON: %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ungültiges JSON: %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μη έγκυρο JSON: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON inválido: %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Virheellinen JSON: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON invalide : %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON לא תקין: %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Érvénytelen JSON: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON tidak valid: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON non valido: %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無効なJSON: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"유효하지 않은 JSON: %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON မှားယွင်းသည်- %@\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugyldig JSON: %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ongeldige JSON: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nieprawidłowy format JSON: %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON inválido: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON inválido: %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON invalid: %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недопустимый JSON: %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neplatný JSON: %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неисправан JSON: %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogiltig JSON: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçersiz JSON: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недійсний JSON: %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"JSON không hợp lệ: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无效的 JSON：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無效的 JSON：%@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無效的 JSON：%@\"\n          }\n        }\n      }\n    },\n    \"Invalid Logitech productID\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ongeldige Logitech-produk-ID\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"معرّف منتج Logitech غير صالح\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nevažeći Logitech productID\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID de producte Logitech no vàlid\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neplatné ID produktu Logitech\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugyldigt Logitech-produkt-ID\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ungültige Logitech-Produkt-ID\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μη έγκυρο Logitech productID\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID de producto Logitech no válido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Virheellinen Logitech-tuotetunnus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID de produit Logitech invalide\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מזהה מוצר Logitech לא חוקי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Érvénytelen Logitech termék-azonosító\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"productID Logitech tidak valid\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID prodotto Logitech non valido\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無効な Logitech プロダクト ID\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"유효하지 않은 Logitech 제품 ID\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မမှန်ကန်သော Logitech productID\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugyldig Logitech-produkt-ID\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ongeldig Logitech-product-ID\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nieprawidłowy identyfikator produktu Logitech\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID de produto Logitech inválido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID de produto Logitech inválido\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ID produs Logitech invalid\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недопустимый productID Logitech\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neplatné ID produktu Logitech\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неважећи Logitech productID\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogiltigt Logitech-produkt-ID\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçersiz Logitech ürün kimliği\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недійсний productID Logitech\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"productID Logitech không hợp lệ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无效的 Logitech 产品 ID\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無效的 Logitech 產品 ID\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無效的 Logitech 產品 ID\"\n          }\n        }\n      }\n    },\n    \"Invalid value\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ongeldige waarde\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قيمة غير صالحة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neispravna vrijednost\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valor no vàlid\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neplatná hodnota\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugyldig værdi\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ungültiger Wert\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μη έγκυρη τιμή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valor inválido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Virheellinen arvo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valeur invalide\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ערך לא תקין\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Érvénytelen érték\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nilai tidak valid\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valore non valido\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無効な値\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"유효하지 않은 값\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တန်ဖိုး မှားယွင်းသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugyldig verdi\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ongeldige waarde\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nieprawidłowa wartość\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valor inválido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valor inválido\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valoare invalidă\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недопустимое значение\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neplatná hodnota\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неисправна вредност\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogiltigt värde\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geçersiz değer\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недійсне значення\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giá trị không hợp lệ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无效的值\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無效的值\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無效的值\"\n          }\n        }\n      }\n    },\n    \"Keyboard\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sleutelbord\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لوحة المفاتيح\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatura\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klávesnice\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatur\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatur\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πληκτρολόγιο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näppäimistö\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clavier\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מקלדת\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Billentyűzet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keyboard\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastiera\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"キーボード\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"키보드\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ကီးဘုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatur\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toetsenbord\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klawiatura\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatură\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keyboard\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klávesnica\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тастатура\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tangentbord\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klavye\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клавіатура\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bàn phím\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"键盘\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鍵盤\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鍵盤\"\n          }\n        }\n      }\n    },\n    \"Keyboard shortcut: %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sleutelbordkortpad: %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اختصار لوحة المفاتيح: %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prečica na tastaturi: %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dreceres de teclat: %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klávesová zkratka: %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastaturgenvej: %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastaturkurzbefehl: %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Συντόμευση πληκτρολογίου: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atajo de teclado: %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pikanäppäin: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Raccourci clavier : %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קיצור מקלדת: %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Billentyűparancs: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pintasan keyboard: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorciatoia da tastiera: %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"キーボードショートカット: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"키보드 단축키: %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ ၏ ကီးဘုတ်လက်ကွက် shortcut\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatursnarveier: %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toetsenbord snelkoppeling %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrót klawiaturowy: %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atalho do teclado: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atalho de teclado: %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Comandă rapidă de la tastatură: %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сочетание клавиш %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klávesová skratka: %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пречица на тастатури: %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tangentbordsgenväg: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klavye kestirmesi: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Комбінація клавіш: %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phím tắt: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"键盘快捷键：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鍵盤快速鍵：%@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鍵盤捷徑鍵：%@\"\n          }\n        }\n      }\n    },\n    \"Keyboard shortcut…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sleutelbordkortpad…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اختصار لوحة المفاتيح…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prečica na tastaturi…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dreceres de teclat…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klávesová zkratka…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastaturgenvej…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastaturkurzbefehl…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Συντόμευση πληκτρολογίου…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atajo de teclado…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pikanäppäin…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Raccourci clavier…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קיצור מקלדת…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Billentyűparancs…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pintasan keyboard…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorciatoia da tastiera…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"キーボードショートカット…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"키보드 단축키…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… ၏ ကီးဘုတ်လက်ကွက် shortcut\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tastatursnarveier…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sneltoetsen…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrót klawiszowy…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atalho de teclado…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atalho de teclado…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Comandă rapidă de la tastatură…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сочетание клавиш…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klávesová skratka…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пречица на тастатури…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tangentbordsgenväg…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klavye kestirmesi…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Комбінація клавіш…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phím tắt…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"键盘快捷键…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鍵盤捷徑鍵…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鍵盤捷徑鍵…\"\n          }\n        }\n      }\n    },\n    \"Launchpad\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Launchpad\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"启动台\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟動台\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"啟動台\"\n          }\n        }\n      }\n    },\n    \"Learn more\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Leer meer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"معرفة المزيد\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saznajte više\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Més informació\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Další informace\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lær mere\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mehr erfahren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μάθετε περισσότερα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Más información\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lue lisää\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En savoir plus\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"למד עוד\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"További információ\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pelajari lebih lanjut\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scopri di più\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"詳細情報\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"더 알아보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပိုမိုလေ့လာပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finn ut mer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Meer informatie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dowiedz się więcej\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saiba mais\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saiba mais\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Află mai multe\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Подробнее\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ďalšie informácie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сазнајте више\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Läs mer\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Daha fazla bilgi edin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Докладніше\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tìm hiểu thêm\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"了解更多\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"了解詳情\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"了解詳情\"\n          }\n        }\n      }\n    },\n    \"Left button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linker knoppie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الزر الأيسر\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lijevo dugme\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botó esquerre\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Levé tlačítko\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Venstre knap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linke Maustaste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αριστερό κουμπί\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botón izquierdo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vasen painike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bouton gauche\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כפתור שמאלי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bal gomb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol kiri\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsante sinistro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左ボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"왼쪽 버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘယ်ဘက်ခလုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Venstre knapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linkerknop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lewy przycisk\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão esquerdo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão esquerdo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buton stânga\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Левая кнопка мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ľavé tlačidlo\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Лево дугме\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vänster knapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sol düğme\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ліва кнопка\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút bên trái\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左鍵\"\n          }\n        }\n      }\n    },\n    \"Linear\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineêr\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"خطي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linearno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineal\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineární\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineær\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linear\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γραμμικό\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineal\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineaarinen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linéaire\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ליניארי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineáris\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linear\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineare\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"リニア\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"선형\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လီနီယာ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineær\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineair\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Liniowe\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linear\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linear\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Liniar\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Линейный\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lineárny\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Линеарно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linjär\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doğrusal\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Лінійний\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tuyến tính\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"线性\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"線性\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"線性\"\n          }\n        }\n      }\n    },\n    \"LinearMouse needs Accessibility permission\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse benodig toeganklikheid toestemming\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يحتاج LinearMouse إلى إذن الوصول\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse zahtjeva dozvolu Pristupačnosti\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse necessita permisos d'Accessibilitat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse vyžaduje oprávnění k použití funkce Zpřístupnění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse skal bruge adgang til Tilgængelighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse benötigt Zugriff auf Bedienungshilfen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Το LinearMouse χρειάζεται άδεια προσβασιμότητας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse necesita permiso de Accesibilidad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse tarvitsee esteettömyysluvan\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse a besoin d'une autorisation d'accessibilité\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse זקוק להרשאות נגישות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A LinearMouse-nak szüksége van a Kisegítő lehetőségek engedélyre\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse memerlukan izin Aksesibilitas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse necessita dei permessi di Accessibilità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouseにはアクセシビリティの許可が必要です\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse는 손쉬운 사용 권한이 필요합니다\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse သည် Accessibility permission ကို ဖွင့်ပေးရန်လိုအပ်ပါသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse trenger Tilgjengelighets-tillatelse\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse heeft Toegankelijkheidstoestemming nodig\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse wymaga uprawnień Dostępności\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse precisa de permissão de Acessibilidade\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse solicita permissão de acessibilidade\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse are nevoie de permisiune de accesibilitate\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse требуется разрешение на Универсальный доступ\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse vyžaduje oprávnenie na Prístupnosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse захтева дозволу за Приступачност\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse behöver tillstånd för tillgänglighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse erişilebilirlik iznine ihtiyaç duyuyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse потребує дозволу на спеціальні можливості\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse cần quyền truy cập vào Trợ năng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse 需要辅助功能权限\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse 需要輔助使用權限\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"LinearMouse 需要輔助使用權限\"\n          }\n        }\n      }\n    },\n    \"Long\" : {\n      \"comment\" : \"Preset label for inertia duration. Means the momentum effect lasts longer.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lank\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"طويل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dugo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Llarg\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dlouhá\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lang\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lang\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μεγάλη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Largo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pitkä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Long\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ארוך\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hosszú\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Panjang\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lungo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"長押し\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"길게\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ရှည်သော\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lang\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lang\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Długi\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Longo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Longo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lung\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Долго\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dlhá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дугачко\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lång\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uzun\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Довго\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dài\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"长\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"長\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"長效\"\n          }\n        }\n      }\n    },\n    \"Look up & data detectors\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soek op & datadetektors\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"البحث وكاشفات البيانات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detektori pretraživanja i podataka\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerca i detectors de dades\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyhledat & detekce dat\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slå op og datagenkendelse\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suche & Datendetektoren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αναζήτηση & ανιχνευτές δεδομένων\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buscar y detectar datos\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Etsi ja datatunnistimet\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recherche et détecteurs de données\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחץ בחוזקה על ה-Trackpad\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keresés és adatérzékelők\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cari & detektor data\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cerca info e rilevatori dati\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"検索とデータ検出\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"찾아보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အချက်အလက် ထုတ်ယူကိရိယာများ နှင့် ရှာဖွေခြင်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slå opp og datadetektorer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opzoeken & data detectors\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyszukaj i wykrywaj dane\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pesquisar e detectores de dados\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visão geral & detectores de dados\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Căutare și detectoare de date\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поиск и детекторы данных\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyhľadávanie a detektory dát\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Претраживање и детектори података\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slå upp och dataidentifierare\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gözat & veri algılama\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пошук та детектори даних\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tra cứu & bộ dò tìm dữ liệu\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查询与数据检测器\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查詢與資料偵測器\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"查詢和資料偵測器\"\n          }\n        }\n      }\n    },\n    \"Loose\" : {\n      \"comment\" : \"Preset label for scroll response. Means softer or less tightly coupled movement.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Los\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرن\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slobodno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lleu\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volná\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Løs\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lose\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Χαλαρό\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suelto\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Löysä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Détendu\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"רופף\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Laza\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Longgar\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"緩い\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"느슨하게\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လျော့ရဲသော\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Løs\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Los\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Luźny\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flexível\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Solto\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Relaxat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Свободная\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voľná\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Лабаво\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mjuk\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gevşek\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Розслаблено\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lỏng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"松\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"寬鬆\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"寬鬆\"\n          }\n        }\n      }\n    },\n    \"Media\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"وسائط\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mediji\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mitjans\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Média\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Medier\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Medien\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πολυμέσα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Multimedia\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Média\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מדיה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Média\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"メディア\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"미디어\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မီဒီယာ အသံအတိုးအကျယ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Multimédia\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mídia\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Медиа\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Médiá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Медији\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Media\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Medya\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Медіа\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phương tiện\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"媒体\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"媒體\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"媒體\"\n          }\n        }\n      }\n    },\n    \"Middle button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Middelste knoppie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الزر الأوسط\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Srednje dugme\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botó central\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prostřední tlačítko\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Midterste knap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mittlere Maustaste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μεσαίο κουμπί\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botón central\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keskipainike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bouton du milieu\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כפתור אמצעי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Középső gomb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol tengah\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsante centrale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中ボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"휠 버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ်ခလုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Midtknapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Middelste knop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Środkowy przycisk\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão do meio\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão do meio\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Butonul din mijloc\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Средняя кнопка мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stredné tlačidlo\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Средње дугме\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mittenknapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Orta düğme\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Середня кнопка\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút ở giữa\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中鍵\"\n          }\n        }\n      }\n    },\n    \"Middle click\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Middelste klik\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"النقر الأوسط\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Srednji klik\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic amb la roda del ratolí\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prostřední klik\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Midterklik\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mittlere Maustaste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μεσαίο κλικ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic central\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keskimmäinen napsautus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic du milieu\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחצן אמצעי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Középső kattintás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik tengah\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic centrale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中クリック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"휠 클릭\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ် ကလစ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Midtklikk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Middelste klik\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Środkowy przycisk\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique do meio\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique central\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic mijlociu\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"СКМ\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stredný klik\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Средњи клик\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mittenklick\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Orta tık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"СКМ\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuột giữa\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中键点击\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中鍵點擊\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中鍵點擊\"\n          }\n        }\n      }\n    },\n    \"Missing key %1$@ at %2$@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ontbrekende sleutel %1$@ by %2$@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"المفتاح المفقود %1$@ في %2$@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nedostaje tipka %1$@ kod %2$@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Funció %1$@ inexistent a %2$@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chybí klíč %1$@ na %2$@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mangler nøgle %1$@ ved %2$@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fehlender Schlüssel %1$@ auf %2$@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Λείπει το κλειδί %1$@ στη διεύθυνση %2$@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Falta la clave %1$@ en %2$@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Puuttuva avain %1$@ kohteessa %2$@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clé %1$@ manquante à %2$@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מפתח חסר %1$@ ב-%2$@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiányzó kulcs: %1$@ (%2$@)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kunci %1$@ tidak ditemukan di %2$@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chiave mancante %1$@ a %2$@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"キー%1$@が%2$@に見つかりません\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%2$@에 키 %1$@ 없음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%2$@ တွင် %1$@ key ကို မတွေ့ရပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Manglende nøkkel %1$@ ved %2$@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sleutel %1$@ ontbreekt op %2$@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brak klucza %1$@ w %2$@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chave %1$@ em falta em %2$@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chave %1$@ ausente em %2$@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cheie lipsă %1$@ la %2$@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отсутствует ключ %1$@ в %2$@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chýba kľúč %1$@ na %2$@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недостаје кључ %1$@ на %2$@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saknar nyckel %1$@ vid %2$@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anahtar %1$@, %2$@ konumunda eksik\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відсутній ключ %1$@ у %2$@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thiếu khóa %1$@ tại %2$@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缺少键 %1$@ 在 %2$@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"遺失金鑰 %1$@，位置：%2$@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"遺失金鑰 %1$@，位置：%2$@\"\n          }\n        }\n      }\n    },\n    \"Mission Control\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Έλεγχος Αποστολής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ミッションコントロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Controle de missão\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görev Kontrol\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mission Control\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"调度中心\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指揮中心\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指揮中心\"\n          }\n        }\n      }\n    },\n    \"Modes\" : {\n      \"comment\" : \"Section title for available interaction modes.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modusse\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الأوضاع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Načini rada\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modes\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Režimy\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilstande\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modi\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Λειτουργίες\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modos\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilat\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modes\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מצבים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Módok\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"モード\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"모드\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပုံစံများ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modi\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modi\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryby\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modos\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modos\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Moduri\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режимы\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Režimy\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режими\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lägen\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режими\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chế độ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"模式\"\n          }\n        }\n      }\n    },\n    \"Modifier Keys\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wysigingsleutels\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مفاتيح التعديل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifikatorske tipke\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tecles modificadores\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifikační klávesy\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kombitaster\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sondertasten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τροποποιητικά πλήκτρα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclas modificadoras\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muokkausnäppäimet\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modificateur de touches\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קיצורי מקלדת\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Módosító Billentyűk\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol Pengubah\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tasti modificatori\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"修飾キー\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"보조 키\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifier ခလုတ်များ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifikasjonstaster\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toetsaanpassingen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klawisze modyfikujące\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclas modificadoras\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Teclas Modificadoras\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modificator de taste\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клавиши модификаторы\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifikačné klávesy\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Модификаторске тастере\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modifieringstangent\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niteleme Tuşları\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Клавіші-модифікатори\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phím bổ trợ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"修饰键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"變更鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"變更鍵\"\n          }\n        }\n      }\n    },\n    \"Monthly\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maandeliks\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"شهري\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mjesečno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mensual\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Měsíčně\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Månedligt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Monatlich\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μηνιαία\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cada mes\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kuukausittain\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tous les mois\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"חודשי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Havonta\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bulanan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogni mese\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"毎月\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"매달\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လ တိုင်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Månedlig\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maandelijks\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Co miesiąc\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mensal\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mensalmente\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lunar\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ежемесячно\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mesačne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Месечно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Månadsvis\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aylık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Щомісяця\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hàng tháng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每月\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每月\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每月\"\n          }\n        }\n      }\n    },\n    \"Mouse\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muis\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الفأرة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Miš\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ratolí\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Myš\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mus\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maus\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ποντίκι\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ratón\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiiri\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Souris\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"עכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egér\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"マウス\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"마우스\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mus\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muis\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mysz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rato\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Мышь\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Myš\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Миш\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mus\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fare\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Миша\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuột\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鼠标\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠\"\n          }\n        }\n      }\n    },\n    \"Mouse Button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muisknop\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"زر الفأرة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dugme miša\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botó del ratolí\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačítko myši\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Museknap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maustasten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κουμπί Ποντικιού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botón del ratón\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiiren painike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bouton de la souris\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחצני העכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egérgomb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol Mouse\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsante del mouse\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"マウスボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"마우스 버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse ခလုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Museknapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muisknop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przycisk Myszy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão do rato\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão do mouse\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Butonul mouse-ului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопка мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tlačidlo myši\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дугме миша\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Musknapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fare Düğmesi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кнопка миші\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút chuột\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鼠标按键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠按鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠按鍵\"\n          }\n        }\n      }\n    },\n    \"Mouse Wheel\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muiswiel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عجلة الفأرة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Točkić miša\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Roda del ratolí\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kolečko myši\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Musehjul\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mausrad\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ροδέλα Ποντικιού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rueda del ratón\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiiren rulla\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Molette de la souris\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלגלת העכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egérkerék\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Roda Mouse\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rotellina del mouse\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"マウスホイール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"마우스 휠\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse ဘီး\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Musehjul\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muiswiel\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kółko myszy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Roda do rato\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Roda do mouse\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Roata mouse-ului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Колесо мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Koliesko myši\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Точак миша\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Musrullning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fare Tekerleği\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Коліщатко миші\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Con lăn chuột\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鼠标滚轮\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠滾輪\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠滾輪\"\n          }\n        }\n      }\n    },\n    \"Move left a space\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skuif een spasie links\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الانتقال إلى اليسار مسافة واحدة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomjeri u lijevo za jedno mjesto\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mou a l'esquerra un espai\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun o pole vlevo\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flyt et Space til venstre\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ein Leerzeichen nach links bewegen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μετακίνηση αριστερά ένα διάστημα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mover a la izquierda un espacio\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siirry yhden tilan vasemmalle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Déplacer vers la gauche d'un espace\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הזז שמאלה חלון\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugrás balra egy helyet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pindah ke ruang di kiri\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sposta a sinistra di uno spazio\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左にスペースを移動する\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"왼쪽으로 Space 이동\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A space အား ဘယ်ဘက်သို့ ရွေးရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flytt et mellomrom til venstre\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beweeg een ruimte naar links\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przejdź w lewo o przestrzeń\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mover um espaço para a esquerda\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mover um espaço para a esquerda\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutare la stânga un spațiu\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"На одно пространство влево\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun o jedno políčko doľava\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Помери лево за један простор\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flytta ett steg åt vänster\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sola bir boşluk kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемістити ліворуч\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Di chuyển sang trái một khoảng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左移动一个空间\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左移動一個空間\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左移動一個空間\"\n          }\n        }\n      }\n    },\n    \"Move right a space\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skuif een spasie regs\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الانتقال إلى اليمين مسافة واحدة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomjeri u desno za jedno mjesto\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mou a la dreta un espai\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun o pole vpravo\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flyt et Space til højre\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ein Leerzeichen nach rechts bewegen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μετακίνηση δεξιά ένα διάστημα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mover un espacio a la derecha\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siirry yhden tilan oikealle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Déplacer vers la droite d'un espace\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הזז ימינה חלון\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugrás jobbra egy helyet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pindah ke ruang di kanan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sposta a destra di uno spazio\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スペースを右に移動する\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오른쪽으로 Space 이동\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A space အား ညာဘက်သို့ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flytt et mellomrom til høyre\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beweeg een ruimte naar rechts\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przejdź w prawo o przestrzeń\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mover um espaço para a direita\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mover um espaço para a direita\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutare la dreapta un spațiu\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"На одно пространство вправо\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun o jedno políčko doprava\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Помери десно за један простор\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Flytta ett steg åt höger\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağa bir boşluk kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемістити праворуч\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Di chuyển sang phải một khoảng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右移动一个空间\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右移動一個空間\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右移動一個空間\"\n          }\n        }\n      }\n    },\n    \"ms\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مللي ثانية\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מילישניות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"mp\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မီလီစက္ကန့်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"мсек\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"мс\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"мс\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ms\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"毫秒\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"毫秒\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"毫秒\"\n          }\n        }\n      }\n    },\n    \"Mute / unmute\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dem / ont-dem\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"كتم الصوت / إلغاء كتم الصوت\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isključi/uključi zvuk\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Silenciar / reactivar\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ztlumit / Odtlumit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slå lyd til/fra\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stummschalten / Stummschaltung aufheben\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σίγαση / κατάργηση σίγασης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Activar/desactivar sonido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mykistä / poista mykistys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muet / Dé-muet\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"השתק\\\\בטל השתקה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Némítás / némítás feloldása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bisukan / suarakan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Attiva / Disattiva audio\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ミュート / ミュート解除\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"소리 끔/켬\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အသံပိတ် / အသံဖွင့်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Demp / opphev demp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dempen aan/uit\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wycisz / odcisz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ativar / desativar som\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutar / Desmutar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dezactivare / activare sunet\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выключить / включить звук\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stlmiť / Zrušiť stlmenie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Утишај / укључи звук\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tysta/avtysta\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sesi kapat / aç\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнути / увімкнути звук\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bật / Tắt tiếng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"静音 / 取消静音\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"靜音 / 取消靜音\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"靜音 / 取消靜音\"\n          }\n        }\n      }\n    },\n    \"Next\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volgende\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التالي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sljedeće\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Següent\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Další\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Næste\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weiter\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επόμενο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Siguiente\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seuraava\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suivant\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הבא\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Következő\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Berikutnya\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Successivo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"進む\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နောက်သို့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neste\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volgende\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Następny\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Próximo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Próximo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Următorul\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Далее\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ďalší\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Следеће\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nästa\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sonraki\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Наступне\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tiếp theo\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一首\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一個\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一個\"\n          }\n        }\n      }\n    },\n    \"Next Space\" : {\n      \"comment\" : \"Gesture action name for switching to the next macOS desktop Space.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volgende spasie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"المساحة التالية\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sljedeći Razmak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espai següent\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Další plocha\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Næste rum\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nächster Space\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επόμενος Χώρος\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espacio siguiente\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seuraava tila\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espace suivant\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"רווח הבא\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Következő hely\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruang Berikutnya\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spazio successivo\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"次のスペース\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다음 스페이스\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နောက် Space\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neste mellomrom\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Volgende ruimte\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Następny pulpit\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espaço seguinte\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Próximo Espaço\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spațiul următor\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Следующее пространство\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ďalší priestor\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Следећи простор\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nästa skrivbord\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sonraki Alan\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Наступний простір\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không gian tiếp theo\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一个空间\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一個空間\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下一個空間\"\n          }\n        }\n      }\n    },\n    \"No action\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geen aksie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لا يوجد إجراء\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nema funkcije\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cap acció\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenastaveno\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen handling\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keine Funktion\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Καμία ενέργεια\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ninguna acción\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ei toimintoa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pas d'action\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ללא פעולה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nincs művelet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tidak ada tindakan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nessuna azione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"何もしない\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"동작 없음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လုပ်ဆောင်ချက်မရှိ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen handling\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geen actie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brak akcji\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não fazer nada\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenhuma ação\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nicio acțiune\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не задано\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Žiadna akcia\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Без акције\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen åtgärd\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eylem yok\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Без дії\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không có hành động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无动作\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無動作\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無動作\"\n          }\n        }\n      }\n    },\n    \"No device selected.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geen toestel gekies.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لم يتم تحديد جهاز.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nije izabran uređaj.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No s'ha seleccionat cap dispositiu.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Není vybráno žádné zařízení.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen enhed valgt.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kein Gerät ausgewählt.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δεν έχει επιλεγεί συσκευή.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No se ha seleccionado ningún dispositivo.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Laitetta ei ole valittu.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aucun appareil sélectionné.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לא נבחר התקן.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nincs kiválasztott eszköz.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tidak ada perangkat yang dipilih.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nessun dispositivo selezionato.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"デバイスが選択されていません。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"선택된 장치가 없습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"စက်ပစ္စည်းတစ်ခုမျှ မရွေးချယ်ရသေးပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen enhet valgt.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geen apparaat geselecteerd.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie wybrano urządzenia.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenhum dispositivo selecionado.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenhum dispositivo selecionado.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niciun dispozitiv selectat.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Устройство не выбрано.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Žiadne zariadenie nie je vybraté.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ниједан уређај није изабран.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen enhet vald.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiçbir aygıt seçilmedi.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пристрій не вибрано.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không có thiết bị nào được chọn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未选择设备。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未選取任何裝置。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未選取裝置。\"\n          }\n        }\n      }\n    },\n    \"None\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geen\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لا شيء\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ništa\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cap\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Žádný\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keine\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κανένα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ninguno\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ei mitään\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aucun\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ללא\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egyik sem\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tidak ada\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nessuno\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"なし\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"없음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မရှိ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brak\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenhum\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenhum\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niciunul\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нет\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Žiadne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ниједан\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingen\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiçbiri\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Немає\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không có\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"无\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"無\"\n          }\n        }\n      }\n    },\n    \"Not specified\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie gespesifiseer nie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"غير محدد\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nije specificirano\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No especificat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nespecifikováno\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ikke angivet\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nicht angegeben\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δεν έχει οριστεί\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"No especificado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ei määritelty\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Non spécifié\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לא צוין\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nincs megadva\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tidak ditentukan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Non specificato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指定なし\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"지정되지 않음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မသတ်မှတ်ရသေးပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ikke spesifisert\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niet gespecificeerd\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie określono\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não especificado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Não especificado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nespecificat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не указано\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nenastavené\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Није наведено\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ej angivet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Belirtilmemiş\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Не вказано\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không xác định\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未指定\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未指定\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未指定\"\n          }\n        }\n      }\n    },\n    \"Off\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Af\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إيقاف\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isključeno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desactivat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vypnuto\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fra\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aus\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ανενεργό\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desactivado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pois päältä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Désactivé\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כבוי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ki\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nonaktif\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disattivato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"オフ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"끔\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပိတ်ထားပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Av\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uit\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyłączone\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desligado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desativado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oprit\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выкл.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vypnuté\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Искључено\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Av\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kapalı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вимкнено\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tắt\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"关闭\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"關閉\"\n          }\n        }\n      }\n    },\n    \"OK\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"حسنا\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"D'acord\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ok\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εντάξει\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceptar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ok\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אישור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"了解\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"확인\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oké\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ОК\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"У реду\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tamam\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Гаразд\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"OK\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"好\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"確認\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"確認\"\n          }\n        }\n      }\n    },\n    \"Open Accessibility\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Open toeganklikheid\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فتح تسهيلات الوصول\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otvori Pristupačnost\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obre Accessibilitat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přejít na obrazovku Zpřístupnění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Åbn Tilgængelighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öffne Bedienungshilfen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Άνοιγμα ρυθμίσεων προσβασιμότητας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abrir Accesibilidad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avaa esteettömyysasetukset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ouvrir Accessibilité\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"פתיחת הרשאות נגישות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kisegítő lehetőségek megnyitása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Buka Aksesibilitas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Apri Accessibilità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アクセシビリティの設定を開く\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"손쉬운 사용 열기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accessibility ကိုဖွင့်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Åpne Tilgjengelighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toegankelijkheid openen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otwórz Dostępność\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abrir Acessibilidade\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abrir Acessibilidade\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deschide Accesibilitate\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Открыть Универсальный доступ\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otvoriť Prístupnosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отвори Приступачност\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Öppna tillgänglighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erişilebilirliği Aç\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відкрити Доступність\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mở Trợ năng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"打开辅助功能\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"打開輔助使用\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"打開輔助使用\"\n          }\n        }\n      }\n    },\n    \"Other App…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ander App…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تطبيق آخر…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Druga aplikacija…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altra app…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jiná aplikace…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anden app…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Andere App…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Άλλη Εφαρμογή…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otra app…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muu sovellus…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autre application…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אפליקציה אחרת…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Másik alkalmazás…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aplikasi Lain…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altra app…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"他のアプリ…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다른 앱…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အခြားအက်ပ်…\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annet program…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Andere app…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inna aplikacja…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Outro App…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Outro App…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altă aplicație…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Другое приложение…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Iná aplikácia…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Друга апликација…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annan app…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diğer Uygulama…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Інша програма…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ứng dụng khác…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"其他应用…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"其他 App…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"其他 App…\"\n          }\n        }\n      }\n    },\n    \"Other Executable…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ander Uitvoerbare…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ملف تنفيذي آخر…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Drugi izvršni fajl…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altre executable…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jiný spustitelný soubor…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Andet eksekverbart program…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Andere ausführbare Datei…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Άλλο Εκτελέσιμο…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otro ejecutable…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muu suoritettava tiedosto…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Autre exécutable…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קובץ הפעלה אחר…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Másik futtatható fájl…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eksekutabel Lain…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Altro eseguibile…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"他の実行可能ファイル…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"다른 실행 파일…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အခြား လုပ်ဆောင်ကိရိယာ…\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annen kjørbar fil…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Andere uitvoerbare bestanden…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inny plik wykonywalny…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Outro Executável…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Outro Executável…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executabil alt…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Другой исполняемый файл…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Iný spustiteľný súbor…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Други извршни програм…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Annan körbar fil…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diğer Çalıştırılabilir Dosya…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Інший виконуваний файл…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tệp thực thi khác…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"其他可执行文件…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"其他可執行檔…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"其他可執行檔…\"\n          }\n        }\n      }\n    },\n    \"Pinch zoom\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knyp-zoom\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكبير/تصغير بالقرص\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zumiranje spajanjem prstiju\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom de pessic\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přiblížit sevřením\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knib for at zoome\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoomen mit zwei Fingern\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μεγέθυνση τσιμπήματος\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pinch zoom\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pellizcar para acercar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tyyppi ja zoomaa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom par pincement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדל בצביטה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kicsípés nagyításhoz\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cubit untuk zoom\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom con due dita\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ピンチズーム\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"확대 또는 축소하기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom ချဲ့/ချုံ့ ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klypezoom\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Knijp zoom\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Powiększanie przez ściskanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ampliação com dois dedos\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom com 2 dedos\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom prin pensetă\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Масштабирование щипком\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zväčšenie priblížením prstov\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зумирање стискањем\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nypa-zoomning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Belirli alanı yakınlaştır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Збільшення пальцем\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thu phóng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"手势缩放\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"手勢縮放\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"手勢縮放\"\n          }\n        }\n      }\n    },\n    \"Play / pause\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Speel / breek\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تشغيل / إيقاف مؤقت\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreni/pauziraj\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reprodueix / pausa\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přehrát / Pozastavit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afspil / sæt på pause\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wiedergabe / Pause\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αναπαραγωγή / παύση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reproducir/pausar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toista / tauko\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jouer / pause\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"נגן\\\\עצור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lejátszás / szünet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Putar / jeda\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Riproduci / Interrompi\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"再生 / 一時停止\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"재생/일시 정지\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖွင့်ရန် / ရပ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spill av / pause\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afspelen / Pauzeren\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odtwarzanie / pauza\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reproduzir / pausar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Play / pause\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Redare / pauză\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Воспроизведение / пауза\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prehrať / pozastaviť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пусти / паузирај\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spela / pausa\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oynat / Duraklat\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відтворити / зупинити\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phát / Tạm dừng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"播放 / 暂停\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"播放 / 暫停\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"播放 / 暫停\"\n          }\n        }\n      }\n    },\n    \"Pointer\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyser\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"المؤشر\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokazivač\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Punter\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurzor\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Markør\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeiger\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δείκτης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cursor\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Osoitin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pointeur\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סמן\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutató\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Penunjuk\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Puntatore\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ポインター\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"포인터\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pointer\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Peker\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanwijzer\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wskaźnik\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cursor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ponteiro\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indicator\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Курсор\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukazovateľ\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показивач\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pekare\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İşaretçi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вказівник\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Con trỏ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指针\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指標\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指標\"\n          }\n        }\n      }\n    },\n    \"Pointer acceleration\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyser-versnelling\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع المؤشر\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzanje pokazivača\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acceleració del punter\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrychlení kurzoru\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Markøracceleration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeigerbeschleunigung\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιτάχυνση δείκτη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleración del puntero\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Osoittimen kiihdytys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accélération du pointeur\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תאוצת סמן העכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutató gyorsulása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akselerasi penunjuk\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione del puntatore\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ポインターの加速\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"포인터 가속\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညွှန်ပြကိရိယာအရှိန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pekeraksellerasjon\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanwijzer versnelling\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przyspieszenie wskaźnika\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração do cursor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração de ponteiro\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare pointer\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ускорение курсора\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrýchlenie ukazovateľa\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Убрзање показивача\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pekaracceleration\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İmleç ivmesi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пришвидшення вказівника\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gia tốc con trỏ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指针加速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指標加速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指標加速度\"\n          }\n        }\n      }\n    },\n    \"Pointer speed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyser-spoed\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سرعة المؤشر\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina pokazivača\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocitat del punter\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlost kurzoru\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Markørens hastighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeigergeschwindigkeit\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ταχύτητα δείκτη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidad del puntero\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Osoittimen nopeus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vitesse du pointeur\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מהירות סמן העכבר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mutató sebessége\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kecepatan penunjuk\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocità del puntatore\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ポインターの速度\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"포인터 속도\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညွှန်ပြကိရိယာ ရွေ့နှုန်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pekerhastighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aanwijzersnelheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prędkość wskaźnika\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade do cursor\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade do ponteiro\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Viteză pointer\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скорость курсора\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchlosť ukazovateľa\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Брзина показивача\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pekarhastighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İmleç hızı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкість вказівника\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tốc độ con trỏ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指针速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指標速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"指標速度\"\n          }\n        }\n      }\n    },\n    \"Preserve native middle-click on links and buttons\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Behou inheemse middel-klik op skakels en knoppies\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الحفاظ على النقر الأوسط الأصلي على الروابط والأزرار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zadržite izvorni klik srednje tipke na vezama i dugmadima\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Conserva el clic central natiu en enllaços i botons\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zachovat nativní prostřední kliknutí na odkazy a tlačítka\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Behold standard mellemklik på links og knapper\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Native Mittelklick-Funktion auf Links und Schaltflächen beibehalten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διατήρηση εγγενούς μεσαίου κλικ σε συνδέσμους και κουμπιά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Conservar el clic central nativo en enlaces y botones\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Säilytä natiivi keskimmäinen napsautus linkeissä ja painikkeissa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Conserver le clic milieu natif sur les liens et les boutons\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שמור על לחיצת אמצע מקורית על קישורים וכפתורים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tartsa meg az alapértelmezett középső kattintást a hivatkozásokon és gombokon\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pertahankan klik tengah asli pada tautan dan tombol\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantieni il clic centrale nativo su link e pulsanti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"リンクやボタンのネイティブな中央クリックを保持\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"링크 및 버튼의 기본 중앙 클릭 유지\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Links နှင့် ခလုတ်များတွင် မူရင်းအလယ်ကလစ် အပြုအမူကို ထိန်းသိမ်းပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bevar innebygd midtklikk på lenker og knapper\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Behoud native middenklik op links en knoppen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zachowaj natywne kliknięcie środkowym przyciskiem myszy na linkach i przyciskach\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Preservar clique do meio nativo em links e botões\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Preservar clique do meio nativo em links e botões\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Păstrează clic-ul din mijloc nativ pe linkuri și butoane\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сохранять стандартное нажатие средней кнопки мыши на ссылках и кнопках\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zachovať natívne kliknutie stredným tlačidlom na odkazy a tlačidlá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Задржи подразумевани средњи клик на линковима и дугмадима\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Behåll ursprunglig mittklick på länkar och knappar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bağlantılarda ve düğmelerde yerel orta tıklamayı koru\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зберегти стандартне середнє клацання на посиланнях і кнопках\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Giữ nguyên chế độ nhấp chuột giữa gốc trên liên kết và nút\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"保留链接和按钮的本机中间键单击\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"保留連結與按鈕的原生中間點擊\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"保留連結和按鈕的原生中間點擊\"\n          }\n        }\n      }\n    },\n    \"Press and hold a button while dragging to trigger gestures like switching desktop spaces or opening Mission Control.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hou 'n knoppie vas terwyl jy sleep om gebare soos om desktop-spasies te verander of Mission Control oop te maak, te aktiveer.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اضغط مع الاستمرار على زر أثناء السحب لتشغيل إيماءات مثل التبديل بين مساحات سطح المكتب أو فتح Mission Control.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pritisnite i držite dugme dok prevlačite da biste pokrenuli geste poput prebacivanja na drugi prostor na radnoj površini ili otvaranja Mission Controla.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén premut un botó mentre arrossegares per activar gestos com canviar d'espais d'escriptori o obrir el Control de missió.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržte tlačítko a přetáhněte jej, abyste aktivovali gesta, jako je přepínání ploch nebo otevření Mission Control.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryk og hold en knap nede, mens du trækker, for at udløse bevægelser som f.eks. at skifte skrivebordsrum eller åbne Mission Control.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Halten Sie eine Schaltfläche gedrückt, während Sie ziehen, um Gesten wie das Wechseln von Desktop-Spaces oder das Öffnen von Mission Control auszulösen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πατήστε και κρατήστε πατημένο ένα κουμπί ενώ σύρετε για να ενεργοποιήσετε χειρονομίες όπως η εναλλαγή χώρων επιφάνειας εργασίας ή το άνοιγμα του Mission Control.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantén pulsado el botón y arrastra para producir gestos como cambiar espacios o abrir Mission Control.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Paina ja pidä painiketta painettuna vetäessäsi aktivoidaksesi eleitä, kuten työpöytätilojen vaihtamista tai Mission Controlin avaamista.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Maintenez un bouton enfoncé tout en faisant glisser pour déclencher des gestes tels que le changement d’espace de bureau ou l’ouverture de Mission Control.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחץ והחזק לחצן תוך כדי גרירה כדי להפעיל מחוות כמו מעבר בין סביבות שולחן עבודה או פתיחת Mission Control.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tartsa lenyomva egy gombot, miközben húzza, hogy olyan gesztusokat aktiváljon, mint az asztali területek közötti váltás vagy a Mission Control megnyitása.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tekan dan tahan tombol sambil menyeret untuk memicu gestur seperti berpindah ruang desktop atau membuka Mission Control.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tieni premuto un pulsante mentre trascini per attivare gesti come il passaggio tra spazi desktop o l'apertura di Mission Control.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ボタンを押したままドラッグして、デスクトップスペースの切り替えやMission Controlの起動などのジェスチャーをトリガーします。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버튼을 누른 상태에서 드래그하여 데스크탑 스페이스 전환 또는 Mission Control 열기와 같은 제스처를 트리거합니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desktop spaces ပြောင်းခြင်း သို့မဟုတ် Mission Control ဖွင့်ခြင်းကဲ့သို့ gesture များကို trigger လုပ်ရန် ဆွဲနေစဉ် ခလုတ်တစ်ခုကို ဖိကိုင်ထားပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trykk og hold en knapp mens du drar for å utløse gester som å bytte skrivebordsområder eller åpne Mission Control.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Houd een knop ingedrukt terwijl u sleept om gebaren te activeren, zoals het wisselen van bureaubladruimtes of het openen van Mission Control.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naciśnij i przytrzymaj przycisk podczas przeciągania, aby aktywować gesty, takie jak przełączanie przestrzeni pulpitu lub otwieranie Mission Control.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mantenha um botão pressionado enquanto arrasta para acionar gestos como alternar entre espaços de desktop ou abrir o Mission Control.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pressione e segure um botão enquanto arrasta para acionar gestos como alternar espaços da área de trabalho ou abrir o Mission Control.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ține apăsat un buton în timp ce tragi pentru a declanșa gesturi precum comutarea spațiilor de lucru sau deschiderea Mission Control.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нажмите и удерживайте кнопку во время перетаскивания, чтобы активировать жесты, такие как переключение рабочих столов или открытие Mission Control.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podržte tlačidlo a zároveň potiahnite, čím spustíte gestá, ako je prepínanie plôch alebo otvorenie Mission Control.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Притисните и задржите дугме док вучете да бисте активирали покрете попут пребацивања радних простора или отварања Mission Control.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Håll ner en knapp medan du drar för att aktivera gester som att byta skrivbordsutrymmen eller öppna Mission Control.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Masaüstü alanları arasında geçiş yapma veya Mission Control'ü açma gibi hareketleri tetiklemek için sürüklerken bir düğmeyi basılı tutun.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Натисніть і утримуйте кнопку під час перетягування, щоб активувати жести, як-от перемикання між просторами робочого столу або відкриття Mission Control.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhấn và giữ một nút trong khi kéo để kích hoạt các cử chỉ như chuyển đổi không gian máy tính hoặc mở Mission Control.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住按钮并拖动以触发切换桌面空间或打开调度中心等手势。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住按鈕並拖移，以觸發切換桌面空間或開啟「預覽」等手勢。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住按鈕並拖曳，以觸發切換桌面空間或開啟「動態桌面」等手勢。\"\n          }\n        }\n      }\n    },\n    \"Previous\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorige\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"السابق\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prethodno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anterior\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Předchozí\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forrige\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zurück\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Προηγούμενο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anterior\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edellinen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Précédent\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הקודם\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Előző\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sebelumnya\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Precedente\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"戻る\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이전\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ရှေ့သို့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forrige\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorige\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poprzedni\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anterior\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anterior\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anterior\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назад\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Predchádzajúci\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Претходно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Föregående\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Önceki\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Назад\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trước đó\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上一首\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上一個\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上一個\"\n          }\n        }\n      }\n    },\n    \"Previous Space\" : {\n      \"comment\" : \"Gesture action name for switching to the previous macOS desktop Space.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorige spasie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"المساحة السابقة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prethodni Razmak\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espai anterior\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Předchozí plocha\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forrige rum\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorheriger Space\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Προηγούμενος Χώρος\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espacio anterior\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Edellinen tila\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espace précédent\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"רווח קודם\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Előző terület\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ruang Sebelumnya\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spazio precedente\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前のスペース\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"이전 스페이스\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ယခင် Space\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Forrige mellomrom\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vorige ruimte\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poprzednia przestrzeń\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espaço Anterior\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Espaço Anterior\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spațiul anterior\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Предыдущее рабочее пространство\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Predchádzajúci priestor\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Претходни простор\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Föregående utrymme\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Önceki Alan\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Попередній простір\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không gian trước đó\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上一个空间\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上一個空間\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上一個空間\"\n          }\n        }\n      }\n    },\n    \"Primary click\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primêre klik\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"النقر الأساسي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lijevi klik\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic principal\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Levý klik\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Venstreklik\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linksklick\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αριστερό κλικ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic izquierdo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ensisijainen napsautus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic gauche\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחצן שמאלי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elsődleges kattintás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik utama\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic sinistro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左クリック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"좌클릭\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘယ်ဘက် ကလစ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primærklikk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linker klik\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lewy przycisk\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique esquerdo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique esquerdo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic primar\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ЛКМ\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ľavý klik\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primarni klik\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vänsterklick\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sol tık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ЛКМ\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuột trái\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左键点击\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左鍵點擊\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左鍵點擊\"\n          }\n        }\n      }\n    },\n    \"Primary double-click\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primêre dubbelklik\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"النقر المزدوج الأساسي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lijevi dupli klik\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doble clic principal\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Levý dvoj-klik\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primært dobbeltklik\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Linker Doppelklick\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύριο διπλό κλικ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doble clic izquierdo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ensisijainen kaksoisnapsautus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Double-clic gauche\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחיצה כפולה ראשית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elsődleges dupla kattintás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik ganda utama\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Doppio clic sinistro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左ダブルクリック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"왼쪽 더블 클릭\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘယ်ဘက် ကလစ် နှစ်ခါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primær dobbeltklikk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dubbelklik links\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podwójne kliknięcie lewym przyciskiem\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Duplo clique esquerdo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique duplo esquerdo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dublu clic primar\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Двойной щелчок левой кнопкой мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ľavý dvojklik\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primarni dvostruki klik\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primärt dubbelklick\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sol çift tıklama\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Подвійний клац ЛКМ\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhấp đúp chính\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左键双击\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左鍵連點兩下\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左鍵連點兩下\"\n          }\n        }\n      }\n    },\n    \"Quartic ease-in-out with the boldest mid-curve.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartiese geleidelike begin en einde met die sterkste middelkurwe.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع وتباطؤ تدريجي رباعي مع أوضح منحنى في الوسط.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartični postepeni početak i završetak s najizraženijom srednjom krivom.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada i sortida suaus quàrtiques amb la corba central més marcada.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartický pozvolný náběh a doznění s nejvýraznější střední křivkou.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk blød start og afslutning met den mest markante midterkurve.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quartischer sanfter Start und sanftes Ende mit der markantesten Mittelkurve.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τεταρτοβάθμια ομαλή έναρξη και λήξη με την πιο έντονη μεσαία καμπύλη.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrada y salida suaves cuárticas con la curva media más marcada.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neljännen asteen pehmeä alku ja loppu kaikkein korostuneimmalla keskikäyrällä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Entrée et sortie douces quartiques avec la courbe centrale la plus marquée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה וסיום הדרגתיים ממעלה רביעית עם עקומת אמצע בולטת במיוחד.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Negyedfokú lágy indulás és lecsengés a leghangsúlyosabb középső ívvel.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out kuartik dengan kurva tengah paling tegas.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out quartico con la curva centrale più marcata.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"中央のカーブが最も力強い、クォーティックのイーズインアウトです。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"중간 곡선이 가장 강하게 드러나는 쿼틱 이즈 인 아웃입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ်ကွေ့ အပြင်းထန်ဆုံးဖြစ်သော quartic ease-in-out ဖြစ်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk myk start og avslutning med den tydeligste midtkurven.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kwartische geleidelijke start en uitloop met de krachtigste middencurve.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodne narastanie i wyhamowanie czwartego stopnia z najmocniejszym środkowym łukiem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out quártico com a curva intermédia mais marcante.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out quártico com a curva central mais marcante.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out cvartic, cu cea mai pronunțată curbă mediană.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квартический ease-in-out с самой выраженной средней частью.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartické ease-in-out s najvýraznejšou strednou krivkou.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квартично ease-in-out са најизраженијом средишњом кривом.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kvartisk ease-in-out med den mest markerade mittkurvan.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En güçlü orta eğriye sahip kuartik ease-in-out.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Квартичний ease-in-out із найвиразнішою середньою кривою.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ease-in-out bậc bốn với đường cong giữa nổi bật nhất.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次缓入缓出，拥有最明显的中段曲线。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次緩入緩出，擁有最明顯的中段曲線。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次緩入緩出，擁有最明顯的中段曲線。\"\n          }\n        }\n      }\n    },\n    \"Quit %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beëindig %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إغلاق %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izlađi iz %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Surt de %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukončit %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afslut %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ beenden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Έξοδος από το %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Salir de %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lopeta %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quitter %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"צא מ-%@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kilépés: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Keluar dari %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chiudi %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@を終了\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 종료\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ အားထွက်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avslutt %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stop %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zamknij %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sair do %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Encerrar %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Părăsește %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Завершить %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukončiť %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Напусти %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sluta: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@'tan çık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вийти з %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thoát %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"退出 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"退出 %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"退出 %@\"\n          }\n        }\n      }\n    },\n    \"Receive beta updates\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ontvang beta-opdaterings\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تلقي تحديثات البيتا\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omogući BETA nadogradnje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rep actualitzacions beta\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Získat beta aktualizace\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modtag betaopdateringer\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beta-Updates erhalten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Λήψη δοκιμαστικών (beta) ενημερώσεων\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recibir actualizaciones beta\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vastaanota beta-päivityksiä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recevoir les mises à jour bêta\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קבל עדכוני בטא\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bétafrissítések fogadása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terima pembaruan beta\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ricevi aggiornamenti beta\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ベータ版のアップデートを受け取る\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"베타 업데이트 받기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beta update များရရှိရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Motta beta-oppdateringer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ontvang bètaversies\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Otrzymuj aktualizacje beta\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Receber atualizações beta\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Receber atualizações beta\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primește versiuni beta\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Получать бета-обновления\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dostávať beta aktualizácie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primaj beta ažuriranja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ta emot beta-uppdateringar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beta güncellemeleri al\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отримувати бета оновлення\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nhận các bản cập nhật thử nghiệm\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"接收测试版本（beta）更新\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"接收 beta 版本更新\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"接收 Beta 版本更新\"\n          }\n        }\n      }\n    },\n    \"Recording\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opname\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسجيل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snimanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gravant\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nahrávám\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Optager\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aufzeichnen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Γίνεται εγγραφή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Grabando\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tallennus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enregistrement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מקליט\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Felvétel\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Merekam\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Registrazione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"記録中\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"입력을 기다리는 중\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မှတ်တမ်းတင်နေပါသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Registrerer\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opnemen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rejestrowanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A gravar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gravando\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Înregistrare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запись\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nahrávanie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snimanje\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inspelning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydediliyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Записування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đang ghi lại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在录制\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在錄製\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"正在錄製\"\n          }\n        }\n      }\n    },\n    \"Reload\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herlaai\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إعادة التحميل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Osvježi\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recarrega\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Načíst znovu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Genindlæs\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neu laden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επαναφόρτωση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recargar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lataa uudelleen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rafraichir\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"טעינה מחדש\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Újratöltés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muat Ulang\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ricarica\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"リロード\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"새로고침\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြန်လည်လုပ်ဆောင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Last inn på nytt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opnieuw laden\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odśwież\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recarregar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recarregar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reîncărcare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Обновить\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obnoviť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Учитај поново\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ladda om\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yenile\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перезавантажити\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tải lại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重新加载\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重新載入\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重新載入\"\n          }\n        }\n      }\n    },\n    \"Reload Config\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herlaai konfigurasie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إعادة تحميل الإعدادات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Osvježi konfiguraciju\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recarrega la configuració\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přenačíst konfiguraci\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Genindlæs konfiguration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurationsdatei neu laden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επαναφόρτωση διάταξης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recargar configuración\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lataa asetukset uudelleen\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recharger la configuration\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"טען הגדרות מחדש\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguráció újratöltése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muat Ulang Konfigurasi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ricarica la configurazione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定を再読み込み\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 새로고침\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Config ကို ပြန်လည်လုပ်ဆောင်ခြင်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Last inn konfigurasjon på nytt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuratie opnieuw laden\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odśwież konfigurację\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recarregar Configuração\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Recarregar configuração\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reîncărcare configurație\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перезагрузить конфигурацию\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Znova načítať konfiguráciu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Učitaj ponovo konfiguraciju\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ladda om konfiguration\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigürasyonu yeniden yükle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перезавантажити налаштування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tải lại cấu hình\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重新加载配置\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重新載入設定\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重新載入設定\"\n          }\n        }\n      }\n    },\n    \"Repeat\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herhaal\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكرار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ponovi\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repeteix\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opakovat\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gentag\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wiederholen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επανάληψη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetir\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toista\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Répéter\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"חזור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ismétlés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ulangi\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ripeti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"繰り返し\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"반복\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြန်လုပ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gjenta\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herhalen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Powtarzaj\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetir\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetir\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetă\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повтор\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opakovať\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Понови\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Upprepa\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tekrarla\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повторювати\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lặp lại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重复\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重複\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"重複\"\n          }\n        }\n      }\n    },\n    \"Repeat on hold\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herhaal op hou\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التكرار عند الاستمرار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ponavljati na zadržavanju\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repeteix en mantenir premut\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opakovat držením\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gentag på hold\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wiederholen beim Halten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επανάληψη κατά το παρατεταμένο πάτημα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetición en espera\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toista painettuna pitämällä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Répéter en boucle\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"חזור עד שהחלצן משוחרר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ismétlés tartáskor\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ulangi saat ditahan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ripeti tenendo premuto il pulsante\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ホールド時に繰り返す\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"길게 눌러 반복\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖိထားသည့် အချိန်တွင် ခဏခဏ လုပ်ဆောင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gjenta ved holdt nede\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herhaal bij ingedrukt houden\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Powtarzaj podczas przytrzymania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetir ao segurar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetir ao manter pressionado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Repetare la menținere\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повторять удерживание\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opakovať pri podržaní\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ponavljaj dok držiš\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Upprepa vid hållning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Basılı tutulduğunda tekrarla\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повторити при утриманні\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lặp lại khi nhấn giữ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住时重复\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住時重複\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住時重複\"\n          }\n        }\n      }\n    },\n    \"Reset timer on mouse up\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herstel timer met muis op\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إعادة تعيين المؤقت عند رفع زر الماوس\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resetiraj tajmer kada se miš podigne\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reinicia el temporitzador en deixar anar el ratolí\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vynulovat časovač po puštění tlačítka\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nulstil timer ved mus op\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Timer bei Mausbewegung zurücksetzen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επαναφορά χρονομέτρου κατά την άνοδο του ποντικιού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resetear temporizador al subir el ratón\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nollaa ajastin hiiren vapautuksen yhteydessä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Réinitialiser le chronomètre quand la souris est relâchée\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אפס טיממר כאשר עכבר לא לחוץ\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Időzítő visszaállítása egér felengedésekor\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Setel ulang pengatur waktu saat mouse dilepas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ripristina il timer allo spostamento in su del mouse\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"マウスアップ時にタイマーをリセット\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"마우스를 올리면 타이머 재설정\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mouse နှိပ်ပြီးချိန်တွင် Timer ပြန်စရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilbakestill timer ved museknapp opp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reset timer bij muis omhoog\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zresetuj licznik po puszczeniu myszy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reiniciar o temporizador ao subir o rato\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reinicia o temporizador ao subir o mouse\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resetare temporizator la ridicarea mouse-ului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сбросить таймер по нажатию кнопки мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resetovať časovač po uvoľnení myši\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Poništi tajmer kada se miš podigne\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Återställ timer vid musuppsläpp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fare düğmesi bırakıldığında zamanlayıcıyı sıfırla\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скинути таймер при миші вгору\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đặt lại thời gian khi thả nút\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"鼠标松开时重置计时器\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠鬆開時重置計時器\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滑鼠松開時重置計時器\"\n          }\n        }\n      }\n    },\n    \"Restore default preset\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herstel verstekvoorinstelling\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"استعادة الإعداد الافتراضي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vrati zadane postavke\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaura el predefinit per defecte\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obnovit výchozí předvolbu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gendan standardforudindstilling\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standard-Voreinstellung wiederherstellen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επαναφορά προεπιλεγμένης προεπιλογής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurar ajuste preestablecido predeterminado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Palauta oletusasetus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurer le préréglage par défaut\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שחזר הגדרות קבועות מוגדרות כברירת מחדל\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alapértelmezett előbeállítás visszaállítása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kembalikan preset bawaan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ripristina preselezione predefinita\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"デフォルトプリセットを復元\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기본 사전 설정 복원\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မူလ preset ကို ပြန်ရယူပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gjenopprett standard forhåndsinnstilling\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Standaardvoorinstelling herstellen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przywróć domyślny preset\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurar predefinição padrão\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurar predefinição padrão\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurare presetare implicită\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Восстановить стандартный пресет\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obnoviť predvolenú predvoľbu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vrati podrazumevani unapred podešeni\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Återställ standardförinställning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Varsayılan ön ayarı geri yükle\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відновити стандартний пресет\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khôi phục cài đặt sẵn mặc định\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"恢复默认预设\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"回復預設值\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"還原預設預設集\"\n          }\n        }\n      }\n    },\n    \"Reveal Config in Finder…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys konfigurasie in Finder…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار الإعدادات في Finder…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži konfiguraciju u Finder-u…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra la configuració al Finder…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přenačíst konfiguraci ve Finderu…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis konfiguration i Finder…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurationsdatei im Finder anzeigen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αποκάλυψη διάταξης στο Finder…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar configuración en el Finder…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä asetukset Finderissa…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher la configuration dans Finder…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג את ההגדרות ב-Finder…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfiguráció megjelenítése a Finderben…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan Konfigurasi di Finder…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra la configurazione nel Finder…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finderの設定を表示…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finder에서 설정 열기…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Config ၏ တည်နေရာကို finder တွင်ပြရန်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis konfigurasjon i Finder…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toon configuratie in Finder…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż konfigurację w Finderze…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar Configuração no Finder…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar configurações no Finder…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișare configurație în Finder…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показать конфигурацию в Finder…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť konfiguráciu vo Finderi…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži konfiguraciju u Finderu…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa konfiguration i Finder…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigürasyon dosyasını Finder ile aç…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відкрити налаштування у Finder…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Xem tệp cấu hình trong Finder…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Finder 中显示配置…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Finder 中揭示設定…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Finder 中揭示設定…\"\n          }\n        }\n      }\n    },\n    \"Reveal in Finder\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onthul in Vinder\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار في Finder\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži u Finder-u\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra al Finder\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobrazit ve Finderu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis i Finder\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Im Finder anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση στον Finder\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar en el Finder\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä Finderissa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher dans Finder\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג ב-Finder\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Megjelenítés a Finderben\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan di Finder\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra nel Finder\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finder で表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finder에서 열기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finder တွင် ပြရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis i Finder\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toon in Finder\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż w Finderze\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar no Finder\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar no Finder\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arată în Finder\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показать в Finder\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť vo Finderi\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прикажи у Finder-у\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa i Finder\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Finder'da göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показати у Finder\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Xem trong Finder\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Finder 中显示\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Finder 中揭示\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Finder 中揭示\"\n          }\n        }\n      }\n    },\n    \"Reverse scrolling\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omgekeerde blaai\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير العكسي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obrni skrolanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inverteix el desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obrácené posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omvendt rulning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollen invertieren\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αντίστροφη κύλιση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Invertir desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Käänteinen vieritys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inverser le sens de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלילה הפוכה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés megfordítása\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balik guliran\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorrimento inverso\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"逆スクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"역방향 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ပြောင်းပြန် Scrolling\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omvendt rulling\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omgekeerd scrollen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odwróć przewijanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inverter deslocação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inverter a rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare inversă\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Инвертированная прокрутка\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obrátené posúvanie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Обрнуто померање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Omvänd rullning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ters kaydırma\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зворотне прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đảo ngược hướng cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"反向滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"反向捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"反向捲動\"\n          }\n        }\n      }\n    },\n    \"Revert to system defaults\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stel terug na stelselverstekwaardes\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"العودة إلى إعدادات النظام الافتراضية\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vrati na tvorničke postavke\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reverteix als valors predeterminats del sistema\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obnovit výchozí nastavení systému\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nulstil til systemets standardindstillinger\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Auf Systemstandardwerte zurücksetzen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επαναφορά στις προεπιλογές συστήματος\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restablecer valores por defecto\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Palauta järjestelmän oletusasetukset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Réinitialiser aux paramètres par défaut\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שחזור להגדרות ברירת מחדל\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visszaállítás a rendszer alapértékeire\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kembalikan ke bawaan sistem\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ripristina impostazioni predefinite\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"システムデフォルトに戻す\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시스템 기본값으로 되돌리기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မူလ setting အတိုင်းပြန်သွားရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tilbakestill til systemstandarder\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Herstel standaard systeeminstellingen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przywróć ustawienia systemowe\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurar predefinições\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Restaurar Padrões\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Revenire la valorile implicite ale sistemului\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Восстановить настройки по умолчанию\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Návrat k predvoleným nastaveniam systému\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vrati na podrazumevane sistemske postavke\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Återställ till systemstandard\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fabrika ayarlarına dön\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повернути типові налаштування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khôi phục về mặc định\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"回退到系统默认值\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"回退到系統預設值\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"恢復到系統預設值\"\n          }\n        }\n      }\n    },\n    \"Rewind\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terugspoel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إرجاع للخلف\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vrati unazad\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rebobina\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přetočit vzad\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spol tilbage\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zurückspulen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αναστροφή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rebobinar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kelaa taaksepäin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Retour en arrière\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הרץ אחורה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visszatekerés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mundur cepat\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Riavvolgi\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"巻き戻し\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"되감기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နောက်သို့ရစ်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spol tilbake\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terugspoelen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń do tyłu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Retroceder\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Retroceder\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare înapoi\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемотка\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pretočiť späť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Premotaj unazad\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spola tillbaka\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geri sar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Перемотати назад\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tua lại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"快退\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"倒轉\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"回帶\"\n          }\n        }\n      }\n    },\n    \"Right button\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Regterknoppie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الزر الأيمن\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desno dugme\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botó dret\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pravé tlačítko\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Højre knap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechte Maustaste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δεξί κουμπί\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botón derecho\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oikea painike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bouton droit\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כפתור ימני\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jobb gomb\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tombol kanan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pulsante destro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右ボタン\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오른쪽 버튼\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညာဘက်ခလုတ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Høyre knapp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechterknop\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prawy przycisk\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão direito\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Botão direito\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Butonul din dreapta\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Правая кнопка мыши\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pravé tlačidlo\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desno dugme\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Högerknapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağ düğme\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Права кнопка\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nút bên phải\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右鍵\"\n          }\n        }\n      }\n    },\n    \"Run shell command…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voer dopkommando uit…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تشغيل أمر Shell…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreni konzolnu komandu…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executa l’ordre de shell…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spusit shell příkaz…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kør shell-kommando…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Shell-Befehl ausführen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εκτέλεση εντολής κελύφους…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ejecutar comando…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suorita komentokehote…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exécuter une commande shell…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הרץ פקודה shell…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Parancssori parancs futtatása…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jalankan perintah shell…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esegui comando da terminale…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Run shell command…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"셸 스크립트 실행…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"…၏ shell command ကို လုပ်ဆောင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kjør skallkommando…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Shellopdracht uitvoeren…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uruchom polecenie…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executar comando shell…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executar comando do shell…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executare comandă shell…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выполнить shell команду…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustiť shell príkaz…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreni komandu ljuske…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kör shell-kommando…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kabuk komutunu çalıştır…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запустити команду оболонки…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chạy lệnh shell…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"运行 shell 命令…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行 shell 指令…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行 shell 指令…\"\n          }\n        }\n      }\n    },\n    \"Run: %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voer uit: %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تشغيل: %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreni: %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executa: %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustit: %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kør: %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausführen: %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εκτέλεση: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ejecutar: %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suorita: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Exécuter : %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מריץ: %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Futtatás: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jalankan: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esegui: %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"実行: %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"실행: %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ အား လုပ်ဆောင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kjør: %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voer %@ uit\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uruchom: %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executar: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executar: %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executare: %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запустить: %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustiť: %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreni: %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kör: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Çalıştır: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запустити: %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chạy: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"运行：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行：%@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"執行：%@\"\n          }\n        }\n      }\n    },\n    \"Running\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Besig om uit te voer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قيد التشغيل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreće se\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"S'està executant\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Běží\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kørende\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktiv\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Τρέχοντες\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ejecutándose\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suoritetaan\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Applications lancées\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"רץ\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Futtatás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Berjalan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In esecuzione\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"実行中のアプリ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"실행 중\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လုပ်ဆောင်နေသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kjører\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actief\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uruchomione\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Em execução\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Executando\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulează\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запущено\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustené\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokrenuto\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kör\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Çalışan\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запущені\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đang hoạt động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"运行中\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"運行中\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"运行中\"\n          }\n        }\n      }\n    },\n    \"Scroll acceleration\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai-versnelling\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzanje pomicanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acceleració del desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrychlení posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullehastighedsacceleration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Beschleunigung\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιτάχυνση κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleración de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityksen kiihdytys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accélération du défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תאוצת גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési gyorsítás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akselerasi gulir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロール加速度\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 가속도\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll အရှိန်မြှင့်တင်မှု\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulleaksellerasjon\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollversnelling\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przyspieszenie przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração de rolagem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare scroll\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ускорение прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrýchlenie posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzanje pomeranja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollacceleration\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma ivmesi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прискорення прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tăng tốc cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动加速\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動加速\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動加速\"\n          }\n        }\n      }\n    },\n    \"Scroll by moving away from an anchor point, similar to Windows middle-click autoscroll.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai deur weg te beweeg van 'n ankerpunt, soortgelyk aan Windows-middelklik-outoblai.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير بالابتعاد عن نقطة ارتكاز، مشابه للتمرير التلقائي للنقر الأوسط في Windows.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomičite se udaljavanjem od sidrišne točke, slično automatskom pomicanju srednjim klikom u Windowsu.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça't allunyant-te d'un punt d'ancoratge, similar al desplaçament automàtic amb el clic central de Windows.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posouvejte se odsunutím od referenčního bodu, podobně jako automatické posouvání prostředním kliknutím ve Windows.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul ved at bevæge dig væk fra et ankerpunkt, ligesom Windows mellemklik autoscroll.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollen Sie, indem Sie sich von einem Ankerpunkt wegbewegen, ähnlich wie beim automatischen Scrollen mit der mittleren Maustaste unter Windows.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κυλίστε μετακινώντας μακριά από ένα σημείο αγκύρωσης, παρόμοιο με την αυτόματη κύλιση μεσαίου κλικ των Windows.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplázate alejándote de un punto de anclaje, similar al desplazamiento automático del clic central de Windows.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä siirtymällä poispäin ankkuripisteestä, samankaltaisesti kuin Windowsin keskinäppäimen automaattinen vieritys.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Faites défiler en vous éloignant d’un point d’ancrage, similaire au défilement automatique du clic milieu de Windows.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול על ידי התרחקות מנקודת עוגן, בדומה לגלילה אוטומטית של לחיצת אמצע ב-Windows.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgessen el egy rögzítési ponttól távolodva, hasonlóan a Windows középső kattintásos automatikus görgetéséhez.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir dengan bergerak menjauh dari titik jangkar, mirip dengan gulir otomatis klik tengah Windows.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri allontanandoti da un punto di ancoraggio, simile allo scorrimento automatico con clic centrale di Windows.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アンカーポイントから離れるようにスクロールします。Windowsの中クリック自動スクロールに似ています。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기준점에서 멀리 이동하여 스크롤합니다. Windows 중앙 클릭 자동 스크롤과 유사합니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Windows middle-click autoscroll ကဲ့သို့ anchor point မှ ဝေးသွားသော လှုပ်ရှားမှုဖြင့် scroll လုပ်ပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull ved å bevege deg bort fra et ankerpunkt, tilsvarende Windows midtklikk-autoskroll.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollen door weg te bewegen van een ankerpunt, vergelijkbaar met de automatische scrollfunctie van de middenklik in Windows.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewijaj, oddalając się od punktu kotwiczenia, podobnie jak automatyczne przewijanie środkowym przyciskiem myszy w systemie Windows.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Role afastando-se de um ponto de ancoragem, semelhante à rolagem automática com clique do meio do mouse no Windows.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Role movendo-se para longe de um ponto de ancoragem, semelhante à rolagem automática do clique do meio do Windows.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulează mișcându-te departe de un punct de ancorare, similar cu derularea automată cu clic din mijloc din Windows.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокручивайте, отводя курсор от точки привязки, аналогично автопрокрутке средней кнопкой мыши в Windows.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posúvajte sa pohybom preč od referenčného bodu, podobne ako automatické posúvanie stredným tlačidlom vo Windowse.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeraj se udaljavanjem od tačke sidrenja, slično automatskom pomeranju srednjeg klika na Windows-u.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolla genom att röra dig bort från en ankarpunkt, liknande Windows mittklicks automatiska scrollning.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bir çapadan uzaklaşarak kaydırın, Windows orta tıklama otomatik kaydırmasına benzer.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокручуйте, віддаляючись від опорної точки, подібно до автопрокручування середнім клацанням у Windows.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn bằng cách di chuyển ra xa điểm neo, tương tự như tự động cuộn bằng nhấp chuột giữa của Windows.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"通过远离锚点滚动，类似于 Windows 中间键自动滚动。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"透過遠離錨點來捲動，類似於 Windows 中間點擊自動捲動。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"透過遠離錨點來捲動，類似於 Windows 中間點擊自動捲動。\"\n          }\n        }\n      }\n    },\n    \"Scroll down\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai af\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير لأسفل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj na dole\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap avall\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun dolů\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul ned\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach unten scrollen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα κάτω\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse hacia abajo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä alas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers le bas\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול למטה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés lefelé\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke bawah\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri in giù\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"아래로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အောက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull ned\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll omlaag\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w dół\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para baixo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para baixo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare în jos\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вниз\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť nadol\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nadole\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolla nedåt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aşağı kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити вниз\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn xuống\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下捲動\"\n          }\n        }\n      }\n    },\n    \"Scroll down %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai af %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير لأسفل %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj na dole %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap avall %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun dolů %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul ned %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach unten scrollen %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα κάτω %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse abajo %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä alas %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers le bas %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול למטה %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés lefelé: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke bawah %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri in basso %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ を下にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 아래로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ အား အောက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull ned %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll omlaag %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w dół %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para baixo %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para baixo %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare în jos %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вниз %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť nadol %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nadole %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolla nedåt %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aşağı kaydır %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити вниз %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn xuống %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上滚动 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下捲動 %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下捲動 %@\"\n          }\n        }\n      }\n    },\n    \"Scroll down…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai af…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير لأسفل…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj dole…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap avall…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun dolů…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul ned…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach unten scrollen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύληση κάτω…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse abajo…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä alas…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers le bas…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול למטה…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés lefelé…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke bawah…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri in basso…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"아래로 스크롤…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… အား အောက််သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull ned…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naar beneden bladeren…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w dół…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para baixo…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para baixo…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare în jos…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вниз…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť nadol…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nadole…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolla nedåt…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aşağı kaydır…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити вниз…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn xuống…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下滚动…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下捲動…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下捲動…\"\n          }\n        }\n      }\n    },\n    \"Scroll inertia\" : {\n      \"comment\" : \"Setting label for momentum that continues after scrolling input stops.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai-traagheid\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قصور التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inercija pomicanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inèrcia del desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Setrvačnost posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulningsinerti\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Trägheit\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αδράνεια κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inercia de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityksen inertia\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inertie du défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אינרציית גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési tehetetlenség\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inersia gulir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inerzia di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロール慣性\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 관성\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll ဆက်လက်လှုပ်ရှားမှု\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulleinertia\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollinertie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inercja przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inércia de rolagem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inércia de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inerție scroll\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Инерция прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zotrvačnosť posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inercija pomeranja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolltröghet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma ataleti\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Інерція прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quán tính cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动惯性\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動慣性\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動慣性\"\n          }\n        }\n      }\n    },\n    \"Scroll left\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai links\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير لليسار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj lijevo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap a l'esquerra\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun vlevo\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul til venstre\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach links scrollen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα αριστερά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazar hacia la izquierda\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä vasemmalle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers la gauche\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול שמאלה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés balra\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke kiri\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri a sinistra\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"왼쪽으로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘယ်ဘက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull til venstre\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll links\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w lewo\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para a esquerda\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a esqueda\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare la stânga\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка влево\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť doľava\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nalevo\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolla åt vänster\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sola kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка ліворуч\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn sang trái\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左捲動\"\n          }\n        }\n      }\n    },\n    \"Scroll left %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle links %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر لليسار %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj lijevo %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap a l'esquerra %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun vlevo %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul til venstre %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach links scrollen %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα αριστερά %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse izquierda %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä vasemmalle %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers la gauche %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול שמאלה %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés balra: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke kiri %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri a sinistra %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ を左にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 왼쪽으로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ အား ဘယ်ဘက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull til venstre %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll links %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w lewo %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para a esquerda %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a esquerda %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați la stânga %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка влево %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť doľava %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nalevo %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolla åt vänster %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sola kaydır %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити ліворуч %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn sang trái %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左滚动 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左捲動 %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左捲動 %@\"\n          }\n        }\n      }\n    },\n    \"Scroll left…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle links…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر لليسار…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj lijevo…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap a l'esquerra…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun vlevo…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul til venstre…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach links scrollen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύληση αριστερά…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse izquierda…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä vasemmalle…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers la gauche…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול שמאלה…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés balra…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke kiri…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri a sinistra…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"왼쪽으로 스크롤…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… အား ဘက်ဘက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull til venstre…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naar links bladeren…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w lewo…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a esquerda…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a esquerda…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați la stânga…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка влево…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť doľava…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nalevo…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla vänster…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sola kaydır…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити ліворуч…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn sang trái…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左滚动…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左捲動…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左捲動…\"\n          }\n        }\n      }\n    },\n    \"Scroll response\" : {\n      \"comment\" : \"Setting label for how quickly scrolling reacts to input movement.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolreaksie\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"استجابة التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odaziv pomicanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resposta del desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odezva posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulningsrespons\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Reaktion\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Απόκριση κύλισης\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll response\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Respuesta de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityksen vaste\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Réponse du défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תגובת גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési válasz\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Respons gulir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Risposta allo scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロール応答\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 응답\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll တုံ့ပြန်မှု\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullerespons\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollreactie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Reakcja przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resposta de rolagem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Resposta de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Răspuns la derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Реакция прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odozva posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odziv skrolovanja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrollrespons\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma tepkisi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Відгук прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phản hồi cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动响应\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動反應\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動反應\"\n          }\n        }\n      }\n    },\n    \"Scroll right\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle regs\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر لليمين\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj desno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap a la dreta\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun vpravo\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul til højre\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach rechts scrollen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα δεξιά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazar hacia la derecha\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä oikealle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers la droite\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול ימינה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés jobbra\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke kanan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri a destra\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오른쪽으로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညာဘက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull til høyre\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll rechts\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w prawo\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para a direita\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a direita\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați la dreapta\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вправо\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť doprava\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri udesno\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla höger\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağa Kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка праворуч\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn sang phải\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右捲動\"\n          }\n        }\n      }\n    },\n    \"Scroll right %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle regs %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر لليمين %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj desno %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap a la dreta %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun vpravo %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul til højre %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach rechts scrollen %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα δεξιά %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse derecha %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä oikealle %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers la droite %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול ימינה %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés jobbra: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke kanan %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri a destra %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ を右にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 오른쪽으로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ အား ညာဘက်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull til høyre %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll rechts %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w prawo %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para a direita %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a direita %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați la dreapta %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вправо %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť doprava %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri udesno %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla höger %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağa kaydır %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити праворуч %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn sang phải %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右滚动 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右捲動 %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右捲動 %@\"\n          }\n        }\n      }\n    },\n    \"Scroll right…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle regs…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر لليمين…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj desno…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap a la dreta…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun vpravo…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul til højre…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach rechts scrollen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύληση δεξιά…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse derecha…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä oikealle…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers la droite…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול ימינה…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés jobbra…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke kanan…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri a destra…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오른쪽으로 스크롤…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… အား ညာဘက်သို့ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull til høyre…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naar rechts bladeren…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w prawo…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a direita…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para a direita…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați la dreapta…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вправо…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť doprava…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri udesno…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla höger…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağa kaydır…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити праворуч…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn sang phải…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右滚动…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右捲動…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右捲動…\"\n          }\n        }\n      }\n    },\n    \"Scroll speed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolspoed\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سرعة التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina pomicanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocitat de desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlost posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulningshastighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Geschwindigkeit\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ταχύτητα κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidad de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityksen nopeus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vitesse de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מהירות גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési sebesség\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kecepatan gulir\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocità di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロール速度\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 속도\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll အမြန်နှုန်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullehastighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollsnelheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prędkość przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade de rolagem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Viteză de derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скорость прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchlosť posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina skrolovanja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrollhastighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma hızı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкість прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tốc độ cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動速度\"\n          }\n        }\n      }\n    },\n    \"Scroll up\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle op\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر للأعلى\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj gore\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap amunt\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun nahoru\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul op\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach oben scrollen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα επάνω\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse hacia arriba\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä ylös\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers le haut\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול למעלה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés felfelé\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke atas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri in su\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"위로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အပေါ်သို့ ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull opp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll omhoog\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w górę\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para cima\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para cima\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați în sus\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вверх\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť nahor\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nagore\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla upp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yukarı kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити вгору\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn lên\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上捲動\"\n          }\n        }\n      }\n    },\n    \"Scroll up %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle op %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر للأعلى %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj gore %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap amunt %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun nahoru %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul op %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach oben scrollen %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση προς τα πάνω %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse arriba %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä ylös %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers le haut %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול למעלה %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés felfelé: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke atas %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri in alto %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ を上にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ 위로 스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%@ အားအပေါ်သို့  ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull opp %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll omhoog %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w górę %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocar para cima %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para cima %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați în sus %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вверх %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť nahor %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nagore %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla upp %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yukarı kaydır %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити вгору %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn lên %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上滚动 %@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上捲動 %@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上捲動 %@\"\n          }\n        }\n      }\n    },\n    \"Scroll up…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolle op…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مرر للأعلى…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolaj gore…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaça cap amunt…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posun nahoru…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rul op…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach oben scrollen…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κλήση επάνω…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazarse arriba…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritä ylös…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défiler vers le haut…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלול למעלה…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés felfelé…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gulir ke atas…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri in alto…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上にスクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"위로 스크롤…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"… အား အပေါ်သို့ရွေ့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rull opp…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Naar boven bladeren…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewiń w górę…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para cima…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolar para cima…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulați în sus…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вверх…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posunúť nahor…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomeri nagore…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolla upp…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yukarı kaydır…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутити вверх…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn lên…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上滚动…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上捲動…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上捲動…\"\n          }\n        }\n      }\n    },\n    \"Scrolling\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blaai\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolanje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κύλιση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetés\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pengguliran\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロール\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulling\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Muiswiel\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewijanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslocação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posúvanie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Померање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動\"\n          }\n        }\n      }\n    },\n    \"Scrolling acceleration\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolversnelling\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تسارع التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzanje skrolanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Acceleració del desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrychlení posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulleacceleration\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollbeschleunigung\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιτάχυνση κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleración de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityksen kiihdytys\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accélération du défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תאוצת גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési gyorsulás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akselerasi pengguliran\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerazione di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロールの加速\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 가속\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling အရှိန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulleaksellerasjon\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blader-acceleratie\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przyspieszenie przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração de deslocação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceleração de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Accelerare derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ускорение прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zrýchlenie posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ubrzanje skrolovanja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullande acceleration\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma ivmesi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пришвидшення прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gia tốc cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动加速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動加速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動加速度\"\n          }\n        }\n      }\n    },\n    \"Scrolling curve\" : {\n      \"comment\" : \"Setting label for the acceleration curve profile applied to scrolling.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolkurwe\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"منحنى التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kriva pomicanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Corba de desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Křivka posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulningskurve\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Kurve\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Καμπύλη κύλισης\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling curve\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curva de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityskäyrä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Courbe de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"עקומת גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési görbe\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurva pengguliran\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curva di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロールカーブ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 곡선\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling မျဉ်းကောက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullekurve\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollcurve\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Krzywa przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curva de rolagem\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curva de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curbă de derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Кривая прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Krivka posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kriva skrolovanja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrollkurva\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma eğrisi\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Крива прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đường cong cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动曲线\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動曲線\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動曲線\"\n          }\n        }\n      }\n    },\n    \"Scrolling is disabled based on the current settings.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rol is gedeaktiveer gebaseer op die huidige instellings.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تم تعطيل التمرير بناءً على الإعدادات الحالية.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrolanje je onemogućeno sa trenutnim postavkama.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"El desplaçament està inhabilitat segons la configuració actual.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posouvání je zakázáno dle aktuálního nastavení.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulning er slået fra baseret på de aktuelle indstillinger.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollen ist aufgrund der aktuellen Einstellungen deaktiviert.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Η κύλιση είναι απενεργοποιημένη με βάση τις τρέχουσες ρυθμίσεις.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"El desplazamiento está desactivado basado en la configuración actual.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritys on poistettu käytöstä nykyisten asetusten perusteella.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le défilement est désactivé selon les paramètres actuels.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גלילה מבוטלת בגלל ההגדרות הנוכחיות.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A görgetés le van tiltva az aktuális beállítások alapján.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pengguliran dinonaktifkan berdasarkan pengaturan saat ini.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorrimento disabilitato in base alle impostazioni correnti.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"現在の設定では、スクロールが無効となっています。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"현재 설정에 따라 스크롤이 비활성화됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လက်ရှိဆက်တင်များအရ Scrolling ကို ပိတ်ထားသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulling er deaktivert basert på gjeldende innstillinger.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollen is uitgeschakeld op basis van de huidige instellingen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przewijanie jest wyłączone zgodnie z obecnymi ustawieniami.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A deslocação está desativada com base nas configurações atuais.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A rolagem está desabilitada baseada nas configurações atuais.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Derularea este dezactivată pe baza setărilor curente.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка отключена на основе текущих настроек.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Posúvanie je zakázané na základe aktuálnych nastavení.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Srolovanje je onemogućeno na osnovu trenutnih postavki.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullning är inaktiverad baserat på de aktuella inställningarna.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mevcut ayarlara göre kaydırma devre dışı.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Прокрутка вимкнена на основі поточних параметрів.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chế độ cuộn đã tắt dựa trên cài đặt hiện tại.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"根据当前设置，滚动已被禁用。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"根據當前設定，捲動已被禁用。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"根據當前設定，捲動已被禁用。\"\n          }\n        }\n      }\n    },\n    \"Scrolling mode\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolmodus\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"وضع التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mod skrolanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode de desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Režim posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulletilstand\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Modus\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Λειτουργία κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritystila\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מצב גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési mód\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mode pengguliran\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modalità di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロールモード\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 모드\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling ပုံစံ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullemodus\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bladermodus\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tryb przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo de deslocação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modo de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mod derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Režim posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Režim skrolovanja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullningsläge\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma modu\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Режим прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chế độ cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动模式\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動模式\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動模式\"\n          }\n        }\n      }\n    },\n    \"Scrolling settings are applied to converted events.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolinstellings word toegepas op omskakelde gebeure.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يتم تطبيق إعدادات التمرير على الأحداث المحولة.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postavke skrolanja primjenjuju se na konvertovane događaje.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La configuració de desplaçament s'aplica als esdeveniments convertits.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nastavení posouvání se aplikuje na převedené události.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulningsindstillinger anvendes på konverterede begivenheder.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die Scroll-Einstellungen werden auf umgewandelte Ereignisse angewendet.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Οι ρυθμίσεις κύλισης εφαρμόζονται σε μετατρεπόμενα συμβάντα.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La configuración de desplazamiento se aplica a los eventos convertidos.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vierityksen asetukset koskevat muunnettuja tapahtumia.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Les paramètres de défilement sont appliqués aux événements convertis.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדרות הגלילה מוחלות על אירועים שהומרו.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A görgetési beállítások a konvertált eseményekre vonatkoznak.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pengaturan pengguliran diterapkan pada peristiwa yang dikonversi.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le impostazioni di scorrimento vengono applicate agli eventi convertiti.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロール設定は変換されたイベントに適用されます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"변환된 이벤트에 스크롤 설정이 적용됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling ဆက်တင်များသည် ပြောင်းလဲထားသော ဖြစ်ရပ်များအပေါ် သက်ရောက်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rulleinnstillinger brukes på konverterte hendelser.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrollinstellingen worden toegepast op geconverteerde gebeurtenissen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ustawienia przewijania są stosowane do przekonwertowanych zdarzeń.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As configurações de rolagem são aplicadas aos eventos convertidos.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As configurações de rolagem são aplicadas aos eventos convertidos.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Setările de derulare se aplică evenimentelor convertite.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Настройки прокрутки применяются к преобразованным событиям.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nastavenia posúvania sa aplikujú na konvertované udalosti.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postavke skrolovanja se primenjuju na konvertovane događaje.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrollinställningar tillämpas på konverterade händelser.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma ayarları dönüştürülen olaylara uygulanır.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Налаштування прокручування застосовуються до перетворених подій.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cài đặt cuộn được áp dụng cho các sự kiện đã chuyển đổi.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动设置应用于转换后的事件。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動設定會套用到轉換的事件。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動設定會套用到轉換的事件。\"\n          }\n        }\n      }\n    },\n    \"Scrolling speed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rolspoed\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سرعة التمرير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina skrolanja\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocitat de desplaçament\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlost posouvání\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullehastighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scroll-Geschwindigkeit\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ταχύτητα κύλισης\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidad de desplazamiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vieritysnopeus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vitesse de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מהירות גלילה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Görgetési sebesség\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kecepatan pengguliran\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocità di scorrimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スクロールの速さ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스크롤 속도\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scrolling အမြန်နှုန်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rullehastighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bladersnelheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prędkość przewijania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade de deslocação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade de rolagem\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Viteză de derulare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скорость прокрутки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchlosť posúvania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina skrolovanja\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skrollhastighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırma hızı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкість прокручування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tốc độ cuộn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"滚动速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"捲動速度\"\n          }\n        }\n      }\n    },\n    \"Secondary click\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sekondêre klik\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"النقر الثانوي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desni klik\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic secundari\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pravý klik\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Højreklik\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechtsklick\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Δεξί κλικ\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic derecho\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toissijainen napsautus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic droit\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לחצן ימני\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Másodlagos kattintás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Klik sekunder\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic destro\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右クリック\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"우클릭\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညာဘက် ကလစ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sekundærklikk\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rechter klik\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prawy przycisk\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique direito\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clique direito\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Clic secundar\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПКМ\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pravý klik\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sekundarni klik\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Höger klick\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağ tık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ПКМ\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuột phải\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右键点击\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右鍵點擊\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右鍵點擊\"\n          }\n        }\n      }\n    },\n    \"Select an executable file\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kies 'n uitvoerbare lêer\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تحديد ملف تنفيذي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odaberi izvršni fajl\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecciona un fitxer executable\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vybrat spustitelný soubor\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vælg en eksekverbar fil\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wählen Sie eine ausführbare Datei aus\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιλογή εκτελέσιμου αρχείου\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seleccione un archivo ejecutable\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valitse suoritettava tiedosto\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sélectionner un fichier exécutable\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בחר קובץ הפעלה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Válasszon ki egy futtatható fájlt\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pilih file eksekutabel\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seleziona un file eseguibile\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"実行可能ファイルを選択\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"실행 파일 선택\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လုပ်ဆောင်နိုင်သော ဖိုင်တစ်ခုကို ရွေးချယ်ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velg en kjørbar fil\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecteer een uitvoerbaar bestand\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wybierz plik wykonywalny\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecionar um arquivo executável\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecionar um arquivo executável\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selectați un fișier executabil\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выберите исполняемый файл\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vybrať spustiteľný súbor\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izaberi izvršnu datoteku\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Välj en körbar fil\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bir çalıştırılabilir dosya seçin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Виберіть виконуваний файл\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chọn một tệp thực thi\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"选择一个可执行文件\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選擇可執行檔\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選取可執行檔\"\n          }\n        }\n      }\n    },\n    \"Select an item from the sidebar\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kies 'n item uit die sybalk\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تحديد عنصر من الشريط الجانبي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odaberite stavku iz bočne trake\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecciona un element de la barra lateral\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vybrat položku z postranního panelu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vælg et emne fra sidebjælken\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wähle ein Element aus der Seitenleiste\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιλογή στοιχείου από την πλαϊνή μπάρα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecciona un elemento de la barra lateral\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valitse kohde sivupalkista\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sélectionner un élément de la barre latérale\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בחר פריט מהסרגל הצדדי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Válasszon ki egy elemet az oldalsávból\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pilih item dari bilah samping\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seleziona un elemento dalla barra laterale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"サイドバーから項目を選択\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"사이드바에서 항목 선택\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sidebar မှ အရာတစ်ခုကို ရွေးချယ်ပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velg et element fra sidepanelet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecteer een item uit de zijbalk\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wybierz element z paska bocznego\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecionar um item da barra lateral\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecionar um item da barra lateral\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selectați un element din bara laterală\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выберите элемент из боковой панели\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vybrať položku z postranného panela\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izaberi stavku iz bočne trake\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Välj ett objekt från sidofältet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kenar çubuğundan bir öğe seçin\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Виберіть елемент із бічної панелі\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chọn một mục từ thanh bên\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"从边栏中选择一项\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"從側邊欄選擇項目\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"從側邊欄選取項目\"\n          }\n        }\n      }\n    },\n    \"Selected\" : {\n      \"comment\" : \"Badge text shown on the currently chosen preset or option.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gekies\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"محدد\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odabrano\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seleccionat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vybráno\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valgt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ausgewählt\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιλεγμένο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seleccionado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valittu\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sélectionné\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"נבחר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiválasztva\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dipilih\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selezionato\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選択済み\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"선택됨\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ရွေးချယ်ထားသည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Valgt\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geselecteerd\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wybrano\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecionado\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selecionado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Selectat\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Выбрано\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vybraté\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izabrano\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vald\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seçili\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вибрано\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đã chọn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已选择\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"選取\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"已選取\"\n          }\n        }\n      }\n    },\n    \"Send once on release\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stuur een keer met loslaat\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إرسال مرة واحدة عند الإفلات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pošalji jednom pri otpuštanju\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Envia un cop en deixar anar\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odeslat jednou při uvolnění\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Send én gang ved slip\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einmal beim Loslassen senden\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αποστολή μία φορά κατά την απελευθέρωση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enviar una vez al soltar\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lähetä kerran vapautettaessa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Envoyer une fois au relâchement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שלח פעם אחת בשחרור\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Küldés egyszer felengedéskor\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kirim sekali saat dilepas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Invia una volta al rilascio\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"離したときに 1 回送信\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"놓을 때 한 번 전송\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လွှတ်လိုက်သော အခါ တစ်ကြိမ် ပို့ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Send én gang ved slipp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eén keer verzenden bij loslaten\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyślij raz po zwolnieniu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enviar uma vez ao soltar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enviar uma vez ao soltar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trimite o dată la eliberare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Отправить один раз при отпускании\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odoslať raz pri uvoľnení\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пошаљи једном при пуштању\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skicka en gång vid släpp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bırakınca bir kez gönder\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Надіслати один раз при відпусканні\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gửi một lần khi nhả\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"松开时发送一次\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"放開時發送一次\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"放開時發送一次\"\n          }\n        }\n      }\n    },\n    \"Settings\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instellings\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الإعدادات\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postavke\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configuració\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nastavení\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indstillinger\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einstellungen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ρυθμίσεις\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Settings\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ajustes\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Asetukset\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Paramètres\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדרות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beállítások\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pengaturan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Impostazioni\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Settings\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Innstillinger\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Instellingen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ustawienia\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurações\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Configurações\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Setări\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Настройки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nastavenia\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Postavke\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inställningar\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ayarlar\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Налаштування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cài đặt\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"设置\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定\"\n          }\n        }\n      }\n    },\n    \"Short\" : {\n      \"comment\" : \"Preset label for inertia duration. Means the momentum effect ends sooner.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kort\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قصير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kratko\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curt\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Krátká\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kort\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kurz\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σύντομη\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Corto\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lyhyt\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Court\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קצר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rövid\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pendek\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Breve\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"短\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"짧음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တိုသော\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kort\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kort\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Krótki\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curta\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Curto\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scurt\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Короткая\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Krátke\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kratko\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kort\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kısa\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Короткий\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ngắn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"短\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"短\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"短\"\n          }\n        }\n      }\n    },\n    \"Show current battery\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys huidige battery\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار البطارية الحالية\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži trenutni nivo baterije\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra la bateria actual\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobrazit aktuální baterii\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis aktuelt batteri\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktuellen Akku anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση τρέχουσας μπαταρίας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar batería actual\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä nykyinen akku\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher la batterie actuelle\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג סוללה נוכחית\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jelenlegi akkumulátor megjelenítése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan baterai saat ini\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra batteria attuale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"現在のバッテリーを表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"현재 배터리 보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လက်ရှိ ဘက်ထရီ ပြပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis gjeldende batteri\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Huidige batterij tonen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż bieżący stan baterii\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar bateria atual\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar bateria atual\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișați bateria curentă\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показать текущий заряд батареи\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť aktuálnu batériu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži trenutnu bateriju\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa aktuell batterinivå\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mevcut pili göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показати поточний заряд батареї\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiển thị pin hiện tại\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示当前电池电量\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示目前電池狀態\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示目前電池\"\n          }\n        }\n      }\n    },\n    \"Show desktop\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys werkblad\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار سطح المكتب\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži radnu površinu\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra l'escriptori\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukázat plochu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis skrivebordet\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desktop anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση επιφάνειας εργασίας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar el escritorio\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä työpöytä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Montrer le bureau\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג שולחן עבודה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Asztal megjelenítése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan desktop\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra desktop\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"デスクトップを表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"데스크탑 보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Screen အားပြရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis skrivebord\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bureaublad weergeven\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż pulpit\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar secretária\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar área de trabalho\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișați desktopul\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показать рабочий стол\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť plochu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži radnu površinu\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa skrivbord\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Masaüstünü göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показати робочий стіл\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiển thị màn hình nền\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示桌面\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示桌面\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示桌面\"\n          }\n        }\n      }\n    },\n    \"Show Desktop\" : {\n      \"comment\" : \"Gesture action name for the macOS command that reveals the desktop.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys Werkblad\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار سطح المكتب\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži Desktop\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra l'escriptori\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobrazit plochu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis skrivebord\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schreibtisch anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση επιφάνειας εργασίας\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar escritorio\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä työpöytä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher le bureau\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג שולחן עבודה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Asztal megjelenítése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan Desktop\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra Scrivania\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"デスクトップを表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"데스크탑 보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desktop ပြပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis skrivebord\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bureaublad tonen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż pulpit\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar Mesa\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar Mesa\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișați Desktopul\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показать рабочий стол\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť plochu\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži radnu površinu\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa skrivbordet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Masaüstünü Göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показати робочий стіл\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiển thị màn hình nền\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"显示桌面\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示桌面\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"顯示桌面\"\n          }\n        }\n      }\n    },\n    \"Show in Dock\" : {\n      \"comment\" : \"Setting label for whether the app icon is shown in the macOS Dock.\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys in Dock\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"إظهار في Dock\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži u Dock-u\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra al Dock\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobrazit v Docku\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis i Dock\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Im Dock anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση στην Dock\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar en el Dock\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä Dockissa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher dans le Dock\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג ב-Dock\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Megjelenítés a Dockban\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan di Dock\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra nel Dock\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dock に表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dock에 보이기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dock တွင် ပြပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis i Dock\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tonen in Dock\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż w Docku\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar no Dock\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar no Dock\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afișați în Dock\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показывать в Dock\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť v Docku\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži u Dock-u\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa i Dock\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dock'ta Göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показувати в Dock\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiển thị trong Dock\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在程序坞中显示\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Dock 中顯示\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在 Dock 中顯示\"\n          }\n        }\n      }\n    },\n    \"Show in menu bar\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wys in menu-balk\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عرض في شريط القوائم\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaži u izbornoj traci\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra a la barra de menús\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobrazovat v řádku nabídek\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis i menulinjen\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In der Menüleiste anzeigen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εμφάνιση στη γραμμή μενού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar en la barra de menú\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä valikkorivillä\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Afficher dans la barre des menus\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הצג בשורת המצב\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Megjelenítés a menüsávban\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tampilkan di bilah menu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostra nella barra dei menu\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"メニューバーに表示\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"메뉴 막대에서 보기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menu bar တွင်ပြရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vis i menylinjen\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toon in menubalk\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokaż w pasku menu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar na barra de menus\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mostrar na barra de menus\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arată in bara de meniu\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показывать в строке меню\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zobraziť v lište\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prikaži u meniju trake\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Visa i menyraden\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menüde göster\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Показувати в рядку меню\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hiển thị trên thanh menu\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在菜单栏中显示\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在選單列中顯示\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"在選單列中顯示\"\n          }\n        }\n      }\n    },\n    \"Slow\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stadig\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بطيء\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sporo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lent\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomalu\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Langsom\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Langsam\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αργή\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hidas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lent\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"איטי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lassú\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lambat\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"遅い\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"느리게\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နှေးရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Treg\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Langzaam\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wolno\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lento\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lento\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lent\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Медленно\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pomalá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Споро\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Långsamt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yavaş\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Повільно\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chậm\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"慢\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"慢\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"慢\"\n          }\n        }\n      }\n    },\n    \"Smart zoom\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Slim zoom\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكبير ذكي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pametni zoom\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom intel·ligent\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chytrá lupa\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smart zoom\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intelligenter Zoom\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Έξυπνη μεγέθυνση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom inteligente\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Älykäs zoomaus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom intelligent\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדלה חכמה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intelligens nagyítás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom cerdas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom smart\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スマートズーム\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스마트 확대\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလိုအလျောက် zoom\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smart zoom\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smart zoom\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inteligentne powiększanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ampliação inteligente\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom inteligente\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom inteligent\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Умное увеличение\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inteligentné zväčšenie\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Паметно зумирање\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Smart zoom\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akıllı yakınlaştırma\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Розумний масштаб\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thu phóng thông minh\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"智能缩放\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"智慧型縮放\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"智慧型縮放\"\n          }\n        }\n      }\n    },\n    \"Smooth\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glad\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سلس\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glatko\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suau\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulá\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glat\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sanft\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ομαλό\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suave\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sulava\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fluide\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"חלק\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sima\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mulus\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fluido\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スムーズ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"스무스\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ချောမွေ့\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jevn\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vloeiend\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Płynne\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fluido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fluido\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fluid\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавный\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Plynulý\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Глатко\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mjuk\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akıcı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Плавний\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mượt\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑\"\n          }\n        }\n      }\n    },\n    \"Smoothed (Beta)\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gevlak (Beta)\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مُنعَّم (تجريبي)\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Izglađeno (Beta)\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suavitzat (Beta)\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyhlazeno (Beta)\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jævnet (Beta)\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geglättet (Beta)\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εξομαλυμένο (Βήτα)\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suavizado (Beta)\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tasoitettu (Beta)\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lissé (Bêta)\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מוחלק (בטא)\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Simított (Béta)\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Diperhalus (Beta)\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Levigato (Beta)\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"スムーズ (ベータ)\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"부드럽게 (베타)\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ချောမွေ့သော (ဘီတာ)\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jevnet (Beta)\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vloeiend (Beta)\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wygładzony (Beta)\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suavizado (Beta)\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suavizado (Beta)\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Netezit (Beta)\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Сглаженный (Бета)\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vyhladený (Beta)\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Изглађено (Бета)\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utjämnad (Beta)\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yumuşatılmış (Beta)\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Згладжений (Бета)\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Làm mịn (Beta)\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑 (测试版)\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑 (測試版)\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"平滑 (測試版)\"\n          }\n        }\n      }\n    },\n    \"Soft start that builds momentum as you keep scrolling.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sagte begin wat momentum opbou soos jy aanhou blaai.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"بداية ناعمة تبني الزخم مع استمرارك في التمرير.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blag početak koji gradi zamah dok nastavljate skrolati.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inici suau que acumula impuls a mesura que continues desplaçant-te.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Měkký začátek, který při dalším posouvání nabírá na hybnosti.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Blød start, der bygger momentum op, jo mere du scroller.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sanfter Start, der mehr Schwung aufbaut, je länger Sie scrollen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ήπια αρχή που χτίζει ορμή όσο συνεχίζετε την κύλιση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inicio suave que gana impulso mientras sigues desplazándote.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pehmeä alku, joka kasvattaa vauhtia skrollauksen jatkuessa.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Départ doux qui prend de l'élan à mesure que vous continuez à faire défiler.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה רכה שבונה תנופה ככל שממשיכים לגלול.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lágy indulás, amely görgetés közben fokozatosan építi a lendületet.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Awal yang lembut, dengan momentum yang terus meningkat saat Anda menggulir.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avvio morbido che accumula slancio mentre continui a scorrere.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"やわらかく始まり、スクロールを続けるほど勢いが増していきます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"부드럽게 시작해 스크롤을 계속할수록 탄력이 쌓입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"နူးညံ့စွာ စတင်ပြီး ဆက်လက် စကရောလုပ်သလို အရှိန်တက်လာသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Myk start som bygger opp fart mens du fortsetter å rulle.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zachte start die meer momentum opbouwt terwijl je blijft scrollen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Łagodny start, który nabiera rozpędu w miarę dalszego przewijania.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Início suave que ganha impulso à medida que continua a deslocar.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Início suave que ganha impulso conforme você continua rolando.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pornire lină care acumulează inerție pe măsură ce continui să derulezi.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Мягкий старт, который наращивает инерцию по мере продолжения прокрутки.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jemný začiatok, ktorý pri ďalšom posúvaní naberá zotrvačnosť.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Благ почетак који гради замах док настављате да скролујете.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mjuk start som bygger upp momentum medan du fortsätter att rulla.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kaydırmaya devam ettikçe ivme kazanan yumuşak bir başlangıç.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"М'який старт, що нарощує інерцію, поки ви продовжуєте прокручувати.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khởi đầu nhẹ, tăng dần quán tính khi bạn tiếp tục cuộn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"起步柔和，随着持续滚动逐渐积累动量。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"起步柔和，隨著持續捲動逐漸累積動量。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"起步柔和，隨著持續捲動逐漸累積動量。\"\n          }\n        }\n      }\n    },\n    \"Some gestures, such as swiping back and forward, may stop working.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sommige gebare, soos om terug en vorentoe te vee, sal dalk nie werk nie.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"قد تتوقف بعض الإيماءات، مثل السحب للخلف وللأمام، عن العمل.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neki pokreti, poput prevlačenja naprijed i nazad, mogu prestati funkcionisati.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alguns gestos, com ara lliscar endavant i enrere, poden deixar de funcionar.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Po aktivaci této volby mohou některá gesta, např. zpět a dopředu, přestat fungovat\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nogle bevægelser, såsom at stryge tilbage og fremad, kan stoppe med at virke.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Manche Gesten, beispielsweise Vor- und Zurück-Wischen, könnten nicht korrekt funktionieren.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μερικές χειρονομίες, όπως το σύρσιμο πίσω και εμπρός, μπορεί να σταματήσουν να λειτουργούν.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Algunos gestos, como el deslizamiento hacia atrás y hacia delante, pueden dejar de funcionar.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jotkin eleet, kuten edestakaisin pyyhkäisy, eivät välttämättä toimi.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Certains gestes, comme le balayage avant et arrière, peuvent cesser de fonctionner.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מחוות מסוימות, דוגמת החלקה קדימה ואחורה, עלולים להפסיק לעבוד.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egyes gesztusok, például az előre és hátra csúsztatás, leállhatnak.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beberapa gestur, seperti geser mundur dan maju, mungkin berhenti berfungsi.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alcuni gesti, come scorrere avanti e indietro, potrebbero smettere di funzionare.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"前後スワイプ等、一部のジェスチャーが動作しなくなる可能性があります。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"앞뒤로 스와이프하는 것과 같은 일부 제스처가 작동하지 않을 수 있습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Swiping back and forward ကဲ့သို့ gestures အချို့သည် အလုပ်မလုပ်တော့နိုင်ပါ။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Noen gester, som å sveipe tilbake og fremover, kan slutte å fungere.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sommige gebaren, zoals heen en weer vegen, kunnen misschien niet meer werken.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niektóre gesty, takie jak przesuwanie wstecz i do przodu, mogą przestać działać.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alguns gestos, como deslizar para trás e para a frente, podem deixar de funcionar.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alguns gestos, como deslizar para a frente e para trás, podem parar de funcionar.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unele gesturi, cum ar fi glisarea înapoi și înainte, pot înceta să funcționeze.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Некоторые жесты, такие как смахивание «назад» и «вперед», могут перестать работать.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niektoré gestá, napríklad potiahnutie prstom dozadu a dopredu, môžu prestať fungovať.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неки гестови, као што су превлачење уназад и унапред, можда више неће функционисати.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vissa gester, som att svepa fram och tillbaka, kan sluta arbeta.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İleri ve geri kaydırma gibi bazı hareketler çalışmayı durdurabilir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Деякі жести, такі як провести вперед і назад, можуть перестати працювати.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Một số cử chỉ như quay lại và chuyển tiếp có thể dừng hoạt động.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"某些手势可能无法正常工作，如滑动后退和前进。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"某些手勢可能無法正常運作，如滑動後退和前進。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"某些手勢可能無法正常工作，如滑動後退和前進。\"\n          }\n        }\n      }\n    },\n    \"Speed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spoed\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"السرعة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocitat\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlost\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hastighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geschwindigkeit\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ταχύτητα\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nopeus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vitesse\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מהירות\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sebesség\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kecepatan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocità\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"速度\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"속도\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမြန်နှုန်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hastighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Snelheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prędkość\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Viteză\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скорость\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchlosť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Брзина\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hastighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hız\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкість\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tốc độ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"速度\"\n          }\n        }\n      }\n    },\n    \"Stable and fluid, with a longer carry than Linear.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabiel en glad, met 'n langer uitloop as Lineêr.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مستقر وسلس، مع استمرار أطول من Linear.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabilno i glatko, s dužim nošenjem od Linearno.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Estable i fluid, amb una continuació més llarga que Lineal.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabilní a plynulá, s delším dozvukem než Lineární.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil og flydende med længere efterløb end Lineær.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil und flüssig, mit längerem Nachlauf als Linear.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σταθερό και ομαλό, με μεγαλύτερη διάρκεια από το Γραμμικό.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Estable y fluido, con una prolongación mayor que Lineal.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vakaa ja sulava, pidemmällä jatkumolla kuin Lineaarinen.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stable et fluide, avec une prolongation plus longue que Linéaire.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"יציב וזורם, עם המשך ארוך יותר מ-Linear.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil és folyamatos, a Lineárisnál hosszabb kifutással.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil dan mulus, dengan daya bawa lebih panjang daripada Linear.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabile e fluido, con un trascinamento più lungo di Linear.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"安定してなめらかで、Linear よりも余韻が長めです。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"안정적이고 부드러우며, 선형보다 더 길게 이어집니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"တည်ငြိမ်ပြီး ချောမွေ့ကာ Linear ထက် ပိုရှည်စွာ ဆက်တင်သည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil og jevn, med lengre etterløp enn Lineær.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabiel en vloeiend, met een langere uitloop dan Lineair.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabilne i płynne, z dłuższym wybrzmieniem niż Liniowe.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Estável e fluido, com uma continuidade mais longa do que Linear.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Estável e fluido, com um arrasto mais longo do que Linear.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil și fluid, cu o inerție mai lungă decât Linear.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Стабильный и плавный, с более длинным продолжением, чем у Linear.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabilný a plynulý, s dlhším dozvukom než Linear.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Стабилно и глатко, са дужим клизањем него Linear.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Stabil och mjuk, med längre efterglid än Linear.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kararlı ve akıcı, Linear'dan daha uzun taşımalı.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Стабільний і плавний, з довшим продовженням, ніж у Linear.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ổn định và mượt mà, với độ trôi dài hơn Linear.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"稳定而流畅，延续感比 Linear 更长。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"穩定而流暢，延續感比 Linear 更長。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"穩定而流暢，延續感比 Linear 更長。\"\n          }\n        }\n      }\n    },\n    \"Start at login\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Begin by aanmelding\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"البَدْء عند تسجيل الدخول\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pokreni na loginu\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inicia a l'inici\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustit při startu systému\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Start ved login\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bei der Anmeldung starten\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Έναρξη κατά την είσοδο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abrir al iniciar sesión\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Käynnistä kirjautuessa\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Démarrer à l''ouverture de session\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הפעל בעת עליית המחשב\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Indítás bejelentkezéskor\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mulai saat masuk\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avvia al login\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ログイン時の自動起動\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"로그인 시 시작\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"စက်ဖွင့်ချိန်တွင် အလိုအလျောက်စတင်ရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Start ved innlogging\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Start bij inloggen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uruchom przy zalogowaniu\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Abrir ao iniciar sessão\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Iniciar ao entrar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pornește la autentificare\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Запуск при входе\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spustiť pri štarte\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Покрени при пријављивању\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Starta vid inloggning\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Başlangıçta çalıştır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Автозапуск\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mở lúc khởi động\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"登录时启动\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"登入時啟動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"登入時啟動\"\n          }\n        }\n      }\n    },\n    \"Swipe down\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee af\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اسحب لأسفل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prevucite prema dolje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Llisca cap avall\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přejet dolů\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Træk ned\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach unten wischen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σύρετε προς τα κάτω\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar hacia abajo\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pyyhkäise alas\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balayer vers le bas\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלקה למטה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lehúzás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geser ke bawah\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri verso il basso\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"下にスワイプ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"아래로 쓸기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အောက်သို့ ပွတ်ဆွဲပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sveip ned\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veeg omlaag\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przesuń w dół\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para baixo\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para baixo\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glisați în jos\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Смахнуть вниз\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Potiahnutie nadol\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Помери надоле\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Svep nedåt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aşağı kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Провести вниз\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuốt xuống\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下轻扫\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下滑動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向下掃動\"\n          }\n        }\n      }\n    },\n    \"Swipe left\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee links\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اسحب لليسار\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prevucite lijevo\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Llisca cap a l'esquerra\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přejet doleva\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Træk til venstre\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach links wischen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σύρετε προς τα αριστερά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar a la izquierda\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pyyhkäise vasemmalle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balayer vers la gauche\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלקה שמאלה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balra húzás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geser ke kiri\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri verso sinistra\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"左にスワイプ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"왼쪽으로 쓸기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဘယ်သို့ ပွတ်ဆွဲပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sveip til venstre\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veeg naar links\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przesuń w lewo\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para a esquerda\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para a esquerda\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glisați la stânga\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Смахнуть влево\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Potiahnutie doľava\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Помери лево\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Svep åt vänster\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sola kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Провести вліво\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuốt sang trái\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左轻扫\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左滑動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向左掃動\"\n          }\n        }\n      }\n    },\n    \"Swipe right\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee regs\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اسحب لليمين\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prevucite desno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Llisca cap a la dreta\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přejet doprava\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Træk til højre\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach rechts wischen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σύρετε προς τα δεξιά\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar a la derecha\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pyyhkäise oikealle\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balayer vers la droite\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלקה ימינה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jobbra húzás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geser ke kanan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri verso destra\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"右にスワイプ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"오른쪽으로 쓸기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ညာသို့ ပွတ်ဆွဲပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sveip til høyre\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veeg naar rechts\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przesuń w prawo\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para a direita\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para a direita\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glisați la dreapta\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Смахнуть вправо\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Potiahnutie doprava\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Помери десно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Svep åt höger\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sağa kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Провести вправо\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuốt sang phải\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右轻扫\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右滑動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向右掃動\"\n          }\n        }\n      }\n    },\n    \"Swipe up\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vee op\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"اسحب لأعلى\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prevucite prema gore\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Llisca cap amunt\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přejet nahoru\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Træk op\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nach oben wischen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σύρετε προς τα πάνω\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desliza hacia arriba\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pyyhkäise ylös\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Balayer vers le haut\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלקה למעלה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Felfelé húzás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Geser ke atas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Scorri verso l'alto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"上にスワイプ\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"위로 쓸기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အပေါ်သို့ ပွတ်ဆွဲပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sveip opp\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veeg omhoog\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Przesuń w górę\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para cima\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deslizar para cima\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Glisați în sus\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Смахнуть вверх\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Potiahnutie nahor\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Помери нагоре\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Svep uppåt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yukarı kaydır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Провести вгору\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vuốt lên\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上轻扫\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上滑動\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"向上掃動\"\n          }\n        }\n      }\n    },\n    \"Switch primary and secondary buttons\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wissel primêre en sekondêre knoppies\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تبديل الأزرار الأساسية والثانوية\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zamijeni primarno i sekundarno dugme\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Canvia els botons primari i secundari\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prohodit primární a sekundární tlačítka\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Skift primær og sekundær knap\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primär- und Sekundärtasten tauschen\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εναλλαγή κύριου και δευτερεύοντος κουμπιού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intercambiar botones primario y secundario\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vaihda ensisijainen ja toissijainen painike\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inverser le bouton principal et secondaire\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"החלפת הכפתורים הראשיים והמשניים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Elsődleges és másodlagos gombok felcserélése\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tukar tombol utama dan sekunder\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inverti i pulsanti primario e secondario\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"プライマリボタンとセカンダリボタンを切り替える\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"주 버튼과 보조 버튼 기능 바꾸기\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Primary and Secondary ခလုတ်များ ပြောင်းလဲရန်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bytt primær- og sekundærknapper\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wissel primaire en secundaire knoppen\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zamień przyciski główny i pomocniczy\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trocar botões primário e secundário\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trocar botões primário e secundário\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Comutați butoanele primar și secundar\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поменять левую и правую кнопки\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prepnúť primárne a sekundárne tlačidlá\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Замени примарно и секундарно дугме\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Byt primär och sekundär knapp\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Birincil ve ikincil düğmeleri değiştir\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поміняти місцями ліву та праву кнопки\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Chuyển đổi nút chính và phụ\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"交换鼠标左右按键\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"切換主要和次要按鍵\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"切換主要和次要按鍵\"\n          }\n        }\n      }\n    },\n    \"Thank you for participating in the beta test.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dankie dat jy deelgeneem het aan die beta-toets.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"شكرا لك على المشاركة في الاختبار التجريبي.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hvala na učestvovanju u BETA testu.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gràcies per participar a la prova beta.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Děkujeme za účast v beta testování.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tak fordi du deltager i betatesten.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vielen Dank für die Teilnahme am Betatest.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Σας ευχαριστούμε για τη συμμετοχή σας στη δοκιμή.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gracias por participar en la prueba beta.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiitos osallistumisestasi beta-testiin.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Merci de votre participation au bêta-test.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תודה שאתה משתתף בתוכנית הבטא.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Köszönjük, hogy részt vett a béta tesztben.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terima kasih telah berpartisipasi dalam uji beta.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Grazie per la partecipazione al beta test.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ベータテストにご参加頂き、ありがとうございます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"베타 테스트에 참여해 주셔서 감사합니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beta test တွင်ပါဝင်မှုအတွက် ကျေးဇူးတင်ပါတယ်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Takk for at du deltar i betatesting.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bedankt voor je deelname aan de bèta-test.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dziękujemy za uczestniczenie w beta testach.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obrigado por participar do teste beta.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Obrigado por participar do teste beta.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vă mulțumim că ați participat la testul beta.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Благодарим Вас за участие в бета-тестировании.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ďakujeme za účasť na beta teste.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Хвала вам што учествујете у бета тестирању.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tack för att du deltar i betatestet.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Beta testine katıldığınız için teşekkürler.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дякуємо за участь у бета-тестуванні.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cảm ơn bạn đã tham gia phiên bản dùng thử.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感谢你参加 beta 测试。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感謝你參與 beta 測試。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感謝你參與 beta 測試。\"\n          }\n        }\n      }\n    },\n    \"The native middle-click check only applies when click once to toggle is enabled.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die inheemse middel-klik-kontrole is slegs van toepassing wanneer eenkeer-om-te-skakel geaktiveer is.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ينطبق فحص النقر الأوسط الأصلي فقط عند تمكين النقر مرة واحدة للتبديل.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Provjera izvornog klika srednje tipke primjenjuje se samo kada je uključeno jednokratno klikanje za prebacivanje.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La comprovació nativa del clic central només s'aplica quan \\\"fes clic una vegada per canviar\\\" està activat.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nativní kontrola prostředního kliknutí platí pouze tehdy, je-li povoleno přepínání jedním kliknutím.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Den native mellemklik-kontrol gælder kun, når \\\"klik én gang for at skifte\\\" er aktiveret.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die native Überprüfung für Mittelklicks gilt nur, wenn „Einmal klicken zum Umschalten“ aktiviert ist.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ο εγγενής έλεγχος μεσαίου κλικ ισχύει μόνο όταν είναι ενεργοποιημένη η επιλογή «Κλικ μία φορά για εναλλαγή».\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La verificación nativa del clic central solo se aplica cuando \\\"hacer clic una vez para alternar\\\" está habilitado.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alkuperäinen keskinäppäimen tarkistus koskee vain, kun kerran napsauttamalla vaihto on käytössä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La vérification native du clic central ne s'applique que lorsque l'option « Cliquer une fois pour basculer » est activée.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בדיקת הלחיצה האמצעית המקורית חלה רק כאשר \\\"לחיצה אחת למעבר\\\" מופעלת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A natív középső kattintás ellenőrzés csak akkor érvényes, ha az egyszeri kattintással történő váltás engedélyezve van.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pemeriksaan klik tengah asli hanya berlaku saat klik sekali untuk mengalihkan diaktifkan.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il controllo nativo del clic centrale si applica solo quando \\\"fai clic una volta per attivare/disattivare\\\" è abilitato.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ネイティブの中クリックチェックは、ワンクリックでトグルが有効な場合にのみ適用されます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기본 중간 클릭 확인은 한 번 클릭하여 전환이 활성화된 경우에만 적용됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ်ကလစ်ကို တစ်ကြိမ်နှိပ်၍ဖွင့်/ပိတ်လုပ်ခြင်းကို အသုံးပြုနေချိန်တွင်သာ မူရင်းအလယ်ကလစ်စစ်ဆေးမှု အကျုံးဝင်ပါသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kontrollen for innebygd midtklikk gjelder bare når «klikk én gang for å veksle» er aktivert.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"De systeemeigen middenklikcontrole is alleen van toepassing wanneer 'één keer klikken om te wisselen' is ingeschakeld.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Natywne sprawdzanie środkowego kliknięcia ma zastosowanie tylko wtedy, gdy włączono opcję „Kliknij raz, aby przełączyć”.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A verificação nativa de clique do meio só se aplica quando \\\"clicar uma vez para alternar\\\" está ativado.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A verificação nativa de clique do meio só se aplica quando 'clicar uma vez para alternar' está ativada.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificarea nativă a clicurilor de mijloc se aplică numai atunci când este activată opțiunea „Faceți clic o dată pentru a comuta”.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Собственная проверка среднего клика применяется только при включенной опции «Щелкнуть один раз для переключения».\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nativná kontrola stredného kliknutia sa uplatňuje iba vtedy, keď je povolené prepínanie jedným kliknutím.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нативна провера средњег клика примењује се само када је омогућено једнократно кликање за пребацивање.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Den inbyggda kontrollen för mittenklick gäller endast när \\\"Klicka en gång för att växla\\\" är aktiverat.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yerel orta tıklama denetimi yalnızca bir kez tıklayarak açma/kapama etkinleştirildiğinde geçerlidir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Рідна перевірка середнього клацання застосовується лише тоді, коли увімкнено «Клацнути один раз для перемикання».\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiểm tra nhấp chuột giữa gốc chỉ áp dụng khi bật \\\"nhấp một lần để chuyển đổi\\\".\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"原生中间键单击检查仅在启用了“单击一次以切换”时适用。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"原生中間點擊檢查僅在啟用「按一下切換」時適用。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"原生中間點擊檢查僅在啟用「點按一次以切換」時適用。\"\n          }\n        }\n      }\n    },\n    \"The native middle-click check only applies when the trigger is middle click without modifier keys.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die inheemse middel-klik-kontrole is slegs van toepassing wanneer die sneller middel-klik sonder wysigingsleutels is.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ينطبق فحص النقر الأوسط الأصلي فقط عندما يكون المشغل هو النقر الأوسط بدون مفاتيح معدلة.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Provjera izvornog klika srednje tipke primjenjuje se samo kada je okidač klik srednje tipke bez modifikatorskih tipki.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La comprovació nativa del clic central només s'aplica quan el desencadenant és el clic central sense tecles modificadores.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nativní kontrola prostředního kliknutí platí pouze tehdy, je-li spouštěčem prostřední kliknutí bez modifikačních kláves.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Den native mellemklik-kontrol gælder kun, når udløseren er et mellemklik uden modifikatortaster.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die native Überprüfung für Mittelklicks gilt nur, wenn der Auslöser ein Mittelklick ohne Modifikatortasten ist.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ο εγγενής έλεγχος μεσαίου κλικ ισχύει μόνο όταν η ενεργοποίηση είναι μεσαίο κλικ χωρίς πλήκτρα τροποποίησης.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La verificación nativa del clic central solo se aplica cuando el disparador es clic central sin teclas modificadoras.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Alkuperäinen keskinäppäimen tarkistus koskee vain, kun laukaisin on keskinäppäin ilman muokkausnäppäimiä.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La vérification native du clic central ne s'applique que lorsque le déclencheur est un clic central sans touches modificatrices.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בדיקת הלחיצה האמצעית המקורית חלה רק כאשר הטריגר הוא לחיצה אמצעית ללא מקשי שינוי.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A natív középső kattintás ellenőrzés csak akkor érvényes, ha a kiváltó tényező középső kattintás módosítóbillentyűk nélkül.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pemeriksaan klik tengah asli hanya berlaku saat pemicu adalah klik tengah tanpa tombol pengubah.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il controllo nativo del clic centrale si applica solo quando il trigger è il clic centrale senza tasti modificatori.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ネイティブの中クリックチェックは、トリガーが修飾キーなしの中クリックの場合にのみ適用されます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기본 중간 클릭 확인은 수정자 키 없이 중간 클릭이 트리거일 때만 적용됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ်ကလစ်ကို modifier keys မပါဘဲ အသုံးပြုသည့်အခါတွင်သာ မူရင်းအလယ်ကလစ်စစ်ဆေးမှု အကျုံးဝင်ပါသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kontrollen for innebygd midtklikk gjelder bare når utløseren er midtklikk uten modifikasjonstaster.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"De systeemeigen middenklikcontrole is alleen van toepassing wanneer de trigger een middenklik is zonder speciale toetsen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Natywne sprawdzanie środkowego kliknięcia ma zastosowanie tylko wtedy, gdy wyzwalaczem jest środkowe kliknięcie bez klawiszy modyfikujących.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A verificação nativa de clique do meio só se aplica quando o gatilho é clique do meio sem teclas modificadoras.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A verificação nativa de clique do meio só se aplica quando o gatilho é clique do meio sem teclas modificadoras.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verificarea nativă a clicurilor de mijloc se aplică numai atunci când declanșatorul este clic de mijloc fără taste modificatoare.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Собственная проверка среднего клика применяется только при использовании среднего клика без клавиш-модификаторов в качестве триггера.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nativná kontrola stredného kliknutia sa uplatňuje iba vtedy, keď je spúšťačom stredné kliknutie bez modifikačných klávesov.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Нативна провера средњег клика примењује се само када је окидач средњи клик без модификаторских тастера.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Den inbyggda kontrollen för mittenklick gäller endast när utlösaren är mittenklick utan modifieringstangenter.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yerel orta tıklama denetimi yalnızca değiştirici tuşlar olmadan orta tıklama tetiklendiğinde geçerlidir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Рідна перевірка середнього клацання застосовується лише тоді, коли тригером є середнє клацання без клавіш-модифікаторів.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiểm tra nhấp chuột giữa gốc chỉ áp dụng khi kích hoạt là nhấp chuột giữa mà không có phím sửa đổi.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"原生中间键单击检查仅在触发器是未按修饰键的中间键单击时适用。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"原生中間點擊檢查僅在觸發條件為不含修飾鍵的中間點擊時適用。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"原生中間點擊檢查僅在觸發條件為不含修飾鍵的中間點擊時適用。\"\n          }\n        }\n      }\n    },\n    \"The trigger is already assigned.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Die sneller is reeds toegewys.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تم تعيين المشغّل بالفعل.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okidač je već dodijeljen.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"El disparador ja està assignat.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spouštěč je již přiřazen.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udløseren er allerede tildelt.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Der Auslöser ist bereits zugewiesen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Η εκκίνηση είναι ήδη εκχωρημένη.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"El disparador ya está asignado.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Liipasin on jo määritetty.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le déclencheur est déjà assigné.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הטריגר כבר מוקצה.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A kiváltó már hozzá van rendelve.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pemicu sudah ditetapkan.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Il trigger è già assegnato.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"このトリガーはすでに割り当てられています。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"트리거가 이미 할당되었습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trigger ကို ရှိပြီးသား သတ်မှတ်ထားသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utløseren er allerede tilordnet.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"De trigger is al toegewezen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyzwalacz jest już przypisany.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"O gatilho já está atribuído.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"O gatilho já está atribuído.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Declanșatorul este deja atribuit.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Триггер уже назначен.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spúšťač je už priradený.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Окидач је већ додељен.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utlösaren är redan tilldelad.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tetikleyici zaten atanmış.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тригер вже призначено.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trigger đã được gán.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"该触发器已被分配。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"此觸發器已被指派。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"此觸發器已被指派。\"\n          }\n        }\n      }\n    },\n    \"This will delete all settings for \\\"%@\\\".\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dit sal alle instellings vir \\\"%@\\\" uitvee.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سيؤدي هذا إلى حذف كافة الإعدادات لـ\\\"%@\\\".\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ovim će se izbrisati sve postavke za \\\"%@\\\".\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Això esborrarà totes les configuracions per a \\\"%@\\\".\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tímto smažete všechna nastavení pro „%@“.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dette vil slette alle indstillinger for \\\"%@\\\".\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dies wird alle Einstellungen für \\\"%@\\\" löschen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αυτό θα διαγράψει όλες τις ρυθμίσεις για το \\\"%@\\\".\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esto eliminará todos los ajustes de \\\"%@\\\".\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tämä poistaa kaikki asetukset kohteelle \\\"%@\\\".\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cela supprimera tous les réglages pour « %@ ».\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"פעולה זו תמחק את כל ההגדרות עבור \\\"%@\\\".\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ez törli az összes beállítást ehhez: „%@”.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ini akan menghapus semua pengaturan untuk \\\"%@\\\".\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Questo eliminerà tutte le impostazioni per \\\"%@\\\".\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"これにより、「%@」の設定がすべて削除されます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"\\\"%@\\\"의 모든 설정이 삭제됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဤသည် \\\"%@\\\" အတွက် ဆက်တင်အားလုံးကို ဖျက်ပစ်ပါမည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dette vil slette alle innstillinger for «%@».\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dit verwijdert alle instellingen voor \\\"%@\\\".\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spowoduje to usunięcie wszystkich ustawień dla „%@”.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isso excluirá todas as configurações para \\\"%@\\\".\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isso excluirá todas as configurações para \\\"%@\\\".\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceasta va șterge toate setările pentru „%@”.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Это удалит все настройки для \\\"%@\\\".\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toto odstráni všetky nastavenia pre „%@“.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ово ће избрисати сва подешавања за „%@“.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detta raderar alla inställningar för \\\"%@\\\".\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bu, \\\"%@\\\" için tüm ayarları silecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Це видалить усі налаштування для \\\"%@\\\".\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thao tác này sẽ xóa tất cả cài đặt cho \\\"%@\\\".\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"这将删除“%@”的所有设置。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"這將刪除「%@」的所有設定。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"這將刪除「%@」的所有設定。\"\n          }\n        }\n      }\n    },\n    \"This will delete all settings for the selected device.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dit sal alle instellings vir die geselekteerde toestel uitvee.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سيؤدي هذا إلى حذف كافة الإعدادات للجهاز المحدد.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ovo će obrisati sve postavke za odabrani uređaj.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Això esborrarà totes les configuracions per al dispositiu seleccionat.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tímto smažete všechna nastavení pro vybrané zařízení.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dette vil slette alle indstillinger for den valgte enhed.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dadurch werden alle Einstellungen für das ausgewählte Gerät gelöscht.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αυτό θα διαγράψει όλες τις ρυθμίσεις για την επιλεγμένη συσκευή.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esto eliminará todas las configuraciones del dispositivo seleccionado.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tämä poistaa kaikki asetukset valitulle laitteelle.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cela supprimera tous les réglages de l'appareil sélectionné.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"פעולה זו תמחק את כל ההגדרות עבור המכשיר שנבחר.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ez törli az összes beállítást a kiválasztott eszközhöz.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ini akan menghapus semua pengaturan untuk perangkat yang dipilih.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Questo eliminerà tutte le impostazioni per il dispositivo selezionato.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"これにより、選択したデバイスの設定がすべて削除されます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"선택한 기기의 모든 설정이 삭제됩니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဤသည် ရွေးချယ်ထားသော စက်ပစ္စည်းအတွက် ဆက်တင်အားလုံးကို ဖျက်ပစ်ပါမည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dette vil slette alle innstillinger for den valgte enheten.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dit verwijdert alle instellingen voor het geselecteerde apparaat.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spowoduje to usunięcie wszystkich ustawień dla wybranego urządzenia.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isso excluirá todas as configurações para o dispositivo selecionado.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Isso excluirá todas as configurações para o dispositivo selecionado.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aceasta va șterge toate setările pentru dispozitivul selectat.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Это удалит все настройки для выбранного устройства.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toto odstráni všetky nastavenia pre vybrané zariadenie.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ово ће избрисати сва подешавања за изабрани уређај.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Detta raderar alla inställningar för den valda enheten.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bu, seçili cihaz için tüm ayarları silecektir.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Це видалить усі налаштування для вибраного пристрою.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thao tác này sẽ xóa tất cả cài đặt cho thiết bị đã chọn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"这将删除所选设备的所有设置。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"這將刪除所選裝置的所有設定。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"這將刪除所選裝置的所有設定。\"\n          }\n        }\n      }\n    },\n    \"Threshold\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Drempel\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عتبة\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prag\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Límit\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prahová hodnota\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tærskel\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Schwelle\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Όριο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Umbral\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kynnysarvo\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seuil\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"סף\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Küszöbérték\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ambang batas\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Soglia\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"しきい値\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"임계값\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အကန့်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Terskel\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Drempelwaarde\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Próg\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Limiar\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Limiar\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prag\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Порог\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prah\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Праг\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tröskelvärde\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eşik\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поріг\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ngưỡng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"阈值\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"臨界值\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"臨界值\"\n          }\n        }\n      }\n    },\n    \"To show the settings, launch %@ again.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Om die instellings te wys, begin %@ weer.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لإظهار الإعدادات، قم بتشغيل %@ مرة أخرى.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Za prikaz postavki, ponovo pokrenite %@.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per mostrar la configuració, inicia %@ de nou.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pro zobrazení nastavení, spusťte %@ znovu.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Start %@ igen for at vise indstillingerne.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Um die Einstellungen anzuzeigen, öffne %@ erneut.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Για να εμφανίσετε τις ρυθμίσεις, εκκινήστε ξανά το %@.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Para mostrar las preferencias, vuelve a lanzar %@.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Näytä asetukset käynnistämällä %@ uudelleen.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pour afficher les paramètres, lancez %@ à nouveau.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"כדי להציג את ההגדרות, פתח את %@ מחדש.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A beállítások megjelenítéséhez indítsa el újra a(z) %@ programot.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Untuk menampilkan pengaturan, buka %@ lagi.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Per mostrare le impostazioni, riapri %@.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定を表示するには、 %@ を再度起動してください。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정을 적용하려면 %@를 재시작하십시오.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Settings များကို ပြရန်၊ %@ ကို ထပ်မံ ဖွင့်ပါ။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"For å vise innstillingene, start %@ igjen.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Start %@ opnieuw om de instellingen te tonen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aby wyświetlić ustawienia, uruchom %@ ponownie.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Para mostrar as configurações, inicie o %@ novamente.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Para mostrar as configurações, execute %@ novamente.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pentru a afișa setările, lansați %@ din nou.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Для отображения настроек перезапустите %@.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pre zobrazenie nastavení, spustite %@ znova.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Да бисте приказали подешавања, поново покрените %@.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Om du vill visa inställningarna, starta %@ igen.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tercihleri görmek için %@'i yeniden başlatın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Щоб показати налаштування, запустіть %@ ще раз.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Để hiển thị cài đặt, hãy mở lại %@.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"要显示设置，再次运行 %@。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"要顯示設定，再次運行 %@。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"要顯示設定，再次運行 %@。\"\n          }\n        }\n      }\n    },\n    \"Tracking speed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spoed van opsporing\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"سرعة التتبع\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brzina trekpeda\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocitat de seguiment\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rychlost vzorkování\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sporingshastighed\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tracking-Geschwindigkeit\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ταχύτητα εντοπισμού\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidad de seguimiento\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Seurantanopeus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vitesse de défilement\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"מהירות מעקב\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Követési sebesség\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kecepatan pelacakan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocità di tracciamento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"トラッキング速度\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"추적 속도\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ခြေရာခံအမြန်နှုန်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sporingshastighet\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tracking snelheid\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Prędkość wskaźnika\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade de rastreamento\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velocidade de rastreamento\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Viteza de urmărire\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Скорость перемещения\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Rýchlosť sledovania\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Брзина праћења\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spårningshastighet\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hareket takibi hızı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Швидкість відстежування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tốc độ di chuột\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"跟踪速度\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"軌跡速度\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"軌跡速度\"\n          }\n        }\n      }\n    },\n    \"Trackpad\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toetsblok\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"لوحة التعقب\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trekped\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pegefelt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Επιφάνεια αφής\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ohjauslevy\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Érintőpad\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"トラックパッド\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"트랙패드\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Styreflate\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gładzik\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Трекпад\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тачпед\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Styrplatta\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"İzleme Dörtgeni\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Трекпад\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trackpad\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"触控板\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"觸控式軌跡板\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"觸控板\"\n          }\n        }\n      }\n    },\n    \"Trigger\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sneller\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"مشغل\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okidač\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desencadenant\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spouštěč\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Udløser\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Auslöser\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ενεργοποίηση\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Disparador\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Laukaisin\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Déclencheur\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"טריגר\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kiváltó ok\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pemicu\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trigger\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"トリガー\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"트리거\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"လှုံ့ဆော်မှု\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utløser\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trigger\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wyzwalacz\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gatilho\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gatilho\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Declanșator\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Триггер\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Spúšťač\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Окидач\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utlösare\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tetikleyici\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Тригер\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kích hoạt\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"触发器\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"觸發條件\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"觸發條件\"\n          }\n        }\n      }\n    },\n    \"Type mismatch: expected %1$@ at %2$@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tipe wanpassing: verwag %1$@ by %2$@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عدم تطابق النوع: متوقع %1$@ عند %2$@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neslaganje tipa: očekivano %1$@ na %2$@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desajust de tipus: s'esperava %1$@ a %2$@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nesprávný typ: očekáváno %1$@ na %2$@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Typeuoverensstemmelse: forventede %1$@ ved %2$@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Typenkonflikt: %1$@ erwartet bei %2$@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ασυμφωνία τύπου: αναμενόταν %1$@ στο %2$@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tipo de datos incorrecto: se esperaba %1$@ en %2$@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tyyppivirhe: odotettiin %1$@ kohdassa %2$@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Incompatibilité de type : %1$@ attendu à %2$@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אי-התאמת סוג: צפוי %1$@ ב-%2$@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Típuseltérés: %1$@ várt itt: %2$@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ketidakcocokan tipe: diharapkan %1$@ di %2$@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mancata corrispondenza del tipo: previsto %1$@ a %2$@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"%1$@を%2$@で予期しています\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"타입 불일치: %2$@에 %1$@ 필요\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အမျိုးအစား မကိုက်ညီပါ- %2$@ တွင် %1$@ ကို မျှော်လင့်သည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Typefeil: forventet %1$@ ved %2$@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Typefout: %1$@ verwacht op %2$@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niezgodność typów: oczekiwano %1$@ pod adresem %2$@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Incompatibilidade de tipo: esperado %1$@ em %2$@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Incompatibilidade de tipo: esperado %1$@ em %2$@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Potrivire incorectă de tip: se aștepta %1$@ la %2$@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Несоответствие типа: ожидался %1$@ в %2$@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nezodpovedajúci typ: očakávané %1$@ na %2$@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неподударност типа: очекивано %1$@ на %2$@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Typmatchning: förväntade %1$@ vid %2$@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tür uyumsuzluğu: %2$@ konumunda %1$@ bekleniyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Невідповідність типу: очікується %1$@ за адресою %2$@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sai kiểu dữ liệu: mong đợi %1$@ tại %2$@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"输入不匹配：预期 %1$@ 在 %2$@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"類型不符：預期為 %1$@，但收到 %2$@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"類型不符：預期為 %2$@ 的 %1$@\"\n          }\n        }\n      }\n    },\n    \"Unit must be empty or \\\"px\\\"\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eenheid moet leeg wees of \\\"px\\\"\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يجب أن تكون الوحدة فارغة أو \\\"px\\\"\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jedinica mora biti prazna ili \\\"px\\\"\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"La unitat ha d'estar buida o ser \\\"px\\\"\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jednotka musí být prázdná nebo „px“\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enhed skal være tom eller \\\"px\\\"\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Einheit muss leer oder \\\"px\\\" sein\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Η μονάδα πρέπει να είναι κενή ή \\\"px\\\"\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unidades debe estar vacío o ser \\\"px\\\"\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yksikön on oltava tyhjä tai \\\"px\\\"\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"L'unité doit être vide ou « px »\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"היחידה חייבת להיות ריקה או \\\"px\\\"\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Az egységnek üresnek vagy \\\"px\\\"-nek kell lennie\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Satuan harus kosong atau \\\"px\\\"\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"L'unità deve essere vuota o \\\"px\\\"\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"単位は空にするか、「px」にする必要があります\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"단위는 공백이거나 \\\"px\\\"이어야 합니다\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ယူနစ်သည် ဗလာ သို့မဟုတ် \\\"px\\\" ဖြစ်ရမည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enheten må være tom eller «px»\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eenheid moet leeg zijn of \\\"px\\\"\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jednostka musi być pusta lub „px”\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A unidade deve estar vazia ou ser \\\"px\\\"\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A unidade deve estar vazia ou ser \\\"px\\\"\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unitatea trebuie să fie goală sau „px”\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Единица измерения должна быть пустой или \\\"px\\\"\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jednotka musí byť prázdna alebo „px“\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Јединица мора бити празна или „px“\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enheten måste vara tom eller \\\"px\\\"\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Birim boş veya \\\"px\\\" olmalıdır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Одиниця вимірювання має бути порожньою або \\\"px\\\"\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đơn vị phải để trống hoặc là \\\"px\\\"\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"单位必须为空或 \\\"px\\\"\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"單位必須為空或「px」\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"單位必須為空或「px」\"\n          }\n        }\n      }\n    },\n    \"UniversalBackForward must be true, false, \\\"backOnly\\\" or \\\"forwardOnly\\\"\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward moet waar, onwaar, \\\"backOnly\\\" of \\\"forwardOnly\\\" wees\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يجب أن تكون UniversalBackForward true أو false أو \\\"backOnly\\\" أو \\\"forwardOnly\\\"\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward mora biti tačno, netačno, \\\"backOnly\\\" ili \\\"forwardOnly\\\"\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward ha de ser true, false, \\\"backOnly\\\" o \\\"forwardOnly\\\"\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward musí být true, false, „backOnly“ nebo „forwardOnly“\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward skal være true, false, \\\"backOnly\\\" eller \\\"forwardOnly\\\"\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward muss true, false, \\\"backOnly\\\" oder \\\"forwardOnly\\\" sein\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Το UniversalBackForward πρέπει να είναι true, false, \\\"backOnly\\\" ή \\\"forwardOnly\\\"\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward debe ser true, false, \\\"backOnly\\\" o \\\"forwardOnly\\\"\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward on oltava true, false, \\\"backOnly\\\" tai \\\"forwardOnly\\\"\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward doit être true, false, « backOnly » ou « forwardOnly »\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward חייב להיות true, false, \\\"backOnly\\\" או \\\"forwardOnly\\\"\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Az UniversalBackForward értéke true, false, \\\"backOnly\\\" vagy \\\"forwardOnly\\\" lehet\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward harus berupa true, false, \\\"backOnly\\\" atau \\\"forwardOnly\\\"\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward deve essere true, false, \\\"backOnly\\\" o \\\"forwardOnly\\\"\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForwardはtrue、false、「backOnly」、または「forwardOnly」にする必要があります\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward는 true, false, \\\"backOnly\\\", \\\"forwardOnly\\\" 중 하나여야 합니다\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward သည် true, false, \\\"backOnly\\\" သို့မဟုတ် \\\"forwardOnly\\\" ဖြစ်ရမည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward må være true, false, «backOnly» eller «forwardOnly»\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward moet true, false, \\\"backOnly\\\" of \\\"forwardOnly\\\" zijn\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward musi mieć wartość true, false, „backOnly” lub „forwardOnly”\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward deve ser true, false, \\\"backOnly\\\" ou \\\"forwardOnly\\\"\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward deve ser true, false, \\\"backOnly\\\" ou \\\"forwardOnly\\\"\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward trebuie să fie true, false, „backOnly” sau „forwardOnly”\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward должен быть true, false, \\\"backOnly\\\" или \\\"forwardOnly\\\"\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward musí byť true, false, „backOnly“ alebo „forwardOnly“\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward мора бити true, false, \\\"backOnly\\\" или \\\"forwardOnly\\\"\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward måste vara true, false, \\\"backOnly\\\" eller \\\"forwardOnly\\\"\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward true, false, \\\"backOnly\\\" veya \\\"forwardOnly\\\" olmalıdır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward має бути true, false, \\\"backOnly\\\" або \\\"forwardOnly\\\"\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward phải là true, false, \\\"backOnly\\\" hoặc \\\"forwardOnly\\\"\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackforward 必须为 true、false、\\\"backOnly\\\" 或 \\\"forwardOnly\\\"\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward 必須為 true、false、「backOnly」或「forwardOnly」\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"UniversalBackForward 必須為 true、false、「backOnly」或「forwardOnly」\"\n          }\n        }\n      }\n    },\n    \"Unknown\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onbekend\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"غير معروف\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepoznato\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desconegut\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neznámé\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukendt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Unbekannt\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Άγνωστο\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desconocido\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tuntematon\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Inconnu\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"לא ידוע\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ismeretlen\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tidak diketahui\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sconosciuto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不明\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"알 수 없음\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မသိပါ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukjent\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Onbekend\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nieznany\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desconhecido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desconhecido\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Necunoscut\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неизвестно\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Neznáme\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Непознато\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okänd\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bilinmiyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Невідомо\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Không xác định\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"未知\"\n          }\n        }\n      }\n    },\n    \"Unsupported encoding, expected UTF-8\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nie-ondersteunde kodering, UTF-8 verwag\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ترميز غير مدعوم، متوقع UTF-8\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodržan text, očekivano UTF-8\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codificació no admesa, s'esperava UTF-8\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodporované kódování, očekáváno UTF-8\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Understøtter ikke kodning, forventede UTF-8\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nicht unterstützte Kodierung, UTF-8 erwartet\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μη υποστηριζόμενη κωδικοποίηση, αναμενόταν UTF-8\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codificación no compatible, debe ser UTF-8\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tuntematon koodaus, odotettiin UTF-8\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Encodage non pris en charge, UTF-8 attendu\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"קידוד לא נתמך, צפוי UTF-8\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nem támogatott kódolás, UTF-8 várt\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enkoding tidak didukung, diharapkan UTF-8\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codifica non supportata, previsto UTF-8\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"サポートされていないエンコーディングです。UTF-8を予期しています\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"지원하지 않는 인코딩, UTF-8 필요\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"မထောက်ပံ့သော ကုဒ်နံပါတ်၊ UTF-8 ကို မျှော်လင့်သည်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kodingen støttes ikke, forventet UTF-8\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Niet-ondersteunde codering, UTF-8 verwacht\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nieobsługiwane kodowanie, oczekiwano UTF-8\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codificação não suportada, esperado UTF-8\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codificação não suportada, esperado UTF-8\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Codificare neacceptată, se aștepta UTF-8\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неподдерживаемая кодировка, ожидался UTF-8\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nepodporované kódovanie, očakávané UTF-8\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Неподржана кодна страница, очекиван UTF-8\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Okänt teckenkodning, förväntade UTF-8\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Desteklenmeyen kodlama, UTF-8 bekleniyor\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Непідтримуване кодування, очікується UTF-8\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mã hóa không được hỗ trợ, mong đợi UTF-8\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不支持的编码，预期为 UTF-8\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不支援的編碼，預期為 UTF-8\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"不支援的編碼，預期為 UTF-8\"\n          }\n        }\n      }\n    },\n    \"Update check interval\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Opdateringskontrole-interval\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"فاصل التحقق من التحديث\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval provjere nadogradnje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval de comprovació d'actualitzacions\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval kontroly aktualizací\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval for opdateringssøgning\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aktualisierungs-Prüfintervall\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Διάστημα ελέγχου ενημερώσεων\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Actualizar el intervalo de verificación\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Päivitysten tarkistusväli\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intervalle de vérification des mises à jour\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"תדירות בדיקת עדכונים\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Frissítések ellenőrzésének gyakorisága\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval pemeriksaan pembaruan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Frequenza di rilevamento degli aggiornamenti\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"アップデートのチェック間隔\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"업데이트 확인 간격\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Update များစစ်ဆေးခြင်း ကာလ\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intervall for oppdateringskontroll\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval controle naar updates\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Częstotliwość sprawdzania aktualizacji\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intervalo de verificação de atualizações\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Atualizar intervalo de verificação\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval de verificare a actualizărilor\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Частота проверки обновлений\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Interval kontroly aktualizácií\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Интервал провере ажурирања\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Intervall för uppdateringskontroll\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Güncelleştirme denetimi sıklığı\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Інтервал перевірки оновлень\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thời gian kiểm tra bản cập nhật\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"更新检查频率\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"檢查更新間隔\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"檢查更新間隔\"\n          }\n        }\n      }\n    },\n    \"Use this when you want to fine-tune the feel yourself.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebruik dit wanneer jy die gevoel self fyn wil instel.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"استخدم هذا عندما تريد ضبط الإحساس بدقة بنفسك.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Koristite ovo kada želite sami fino podesiti osjećaj.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Fes servir això quan vulguis ajustar tu mateix la sensació al detall.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Použijte toto, když si chcete odezvu doladit sami.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Brug denne, når du selv vil finjustere fornemmelsen.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verwenden Sie dies, wenn Sie das Gefühl selbst fein abstimmen möchten.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Χρησιμοποιήστε το όταν θέλετε να ρυθμίσετε μόνοι σας με ακρίβεια την αίσθηση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usa esto cuando quieras ajustar la sensación tú mismo con precisión.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Käytä tätä, kun haluat hienosäätää tuntumaa itse.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Utilisez ceci lorsque vous voulez affiner vous-même la sensation.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"השתמשו בזה כשאתם רוצים לכוונן בעצמכם את התחושה.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Akkor használd, ha saját magad szeretnéd finomhangolni az érzetet.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gunakan ini jika Anda ingin menyetel nuansanya sendiri.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Usalo quando vuoi regolare tu stesso la sensazione.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"感触を自分で細かく調整したい場合に使います。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"느낌을 직접 세밀하게 조정하고 싶을 때 사용하세요.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ခံစားမှုကို ကိုယ်တိုင် အသေးစိတ်ညှိချင်သည့်အခါ အသုံးပြုပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bruk denne når du vil finjustere følelsen selv.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Gebruik dit als je het gevoel zelf nauwkeurig wilt afstemmen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Użyj tego, jeśli chcesz samodzielnie precyzyjnie dostroić odczucia.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Use esta opção quando quiser afinar manualmente a sensação.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Use isto quando quiser ajustar a sensação por conta própria.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Folosește această opțiune când vrei să reglezi fin senzația după preferințele tale.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Используйте этот вариант, если хотите самостоятельно тонко настроить отклик.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Použite túto možnosť, keď si chcete odozvu doladiť sami.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Користите ово када желите сами фино да подесите осећај.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Använd detta när du själv vill finjustera känslan.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hissi kendiniz ince ayarlamak istediğinizde bunu kullanın.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Використовуйте це, якщо хочете самостійно точно налаштувати відчуття.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dùng tùy chọn này khi bạn muốn tự tinh chỉnh cảm giác.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"当你想自行微调手感时，请使用这个选项。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"當你想自行微調手感時，請使用這個選項。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"當你想自行微調手感時，請使用這個選項。\"\n          }\n        }\n      }\n    },\n    \"Version: %@\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weergawe: %@\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"الإصدار: %@\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verzija: %@\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versió: %@\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verze %@\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version: %@\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version: %@\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Έκδοση: %@\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versión: %@\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versio: %@\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version : %@\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"גרסה: %@\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verzió: %@\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versi: %@\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versione: %@\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"バージョン %@\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"버전: %@\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဗားရှင်း %@\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versjon: %@\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versie: %@\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wersja: %@\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versão: %@\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versão: %@\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Versiune: %@\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Версия: %@\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verzia: %@\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Верзија: %@\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Version: %@\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sürüm: %@\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Версія: %@\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Phiên bản: %@\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本：%@\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本：%@\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"版本：%@\"\n          }\n        }\n      }\n    },\n    \"Vertical\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikaal\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عمودي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikalno\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikální\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikal\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikal\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Κατακόρυφη\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pystysuora\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"אנכי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Függőleges\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikal\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verticale\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"縦方向\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"수직 방향\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဒေါင်လိုက်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikal\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verticaal\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pionowo\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertical\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вертикальная\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikálne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вертикално\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vertikal\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dikey\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вертикальне\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cuộn dọc\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"纵向\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"縱向\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"縱向\"\n          }\n        }\n      }\n    },\n    \"Very fast quartic pickup with a crisp release.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Baie vinnige kwartiese aanvang met 'n skerp vrylating.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"انطلاقة رباعية سريعة جدًا مع تحرر حاد.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vrlo brz kvartični početak sa čistim otpuštanjem.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arrencada quartica molt ràpida amb un alliberament net.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Velmi rychlý kvartický nástup s ostrým uvolněním.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Meget hurtig kvartisk start med en skarp frigivelse.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sehr schneller quartischer Beginn mit klarem Ausklang.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πολύ γρήγορο τεταρτοβάθμιο ξεκίνημα με καθαρή αποδέσμευση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arranque cuártico muy rápido con una liberación nítida.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erittäin nopea neljännen asteen aloitus terävällä vapautuksella.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Départ quartique très rapide avec un relâchement net.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"התחלה ממעלה רביעית מהירה מאוד עם שחרור חד.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nagyon gyors negyedfokú indulás, feszes lecsengéssel.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tanggapan kuartik yang sangat cepat dengan pelepasan yang tegas.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Avvio quartico molto rapido con un rilascio netto.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"非常に速いクォーティックの立ち上がりと、キレのある抜けが特徴です。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"매우 빠른 쿼틱 반응과 또렷한 풀림이 특징입니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလွန်မြန်သော quartic စတင်မှုနှင့် ပြတ်သားသော အဆုံးပိုင်းရှိသည်။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Svært rask kvartisk respons med en skarp avslutning.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zeer snelle kwartische oppak met een strakke uitloop.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bardzo szybkie wejście czwartego stopnia z wyraźnym wybrzmieniem.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arranque quártico muito rápido com uma libertação nítida.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Arranque quártico muito rápido com uma soltura nítida.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pornire cvartică foarte rapidă, cu eliberare clară și precisă.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Очень быстрый квартический старт с четким отпусканием.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veľmi rýchly kvartický nástup s čistým uvoľnením.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Врло брз квартни почетак са јасним отпуштањем.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mycket snabb kvartisk uppbyggnad med ett tydligt avslut.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Net bir bırakışla çok hızlı kuartik başlangıç.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Дуже швидкий квартичний старт із чітким вивільненням.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khởi đầu bậc bốn rất nhanh với nhịp nhả dứt khoát.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次曲线起步极快，释放干脆利落。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次曲線起步極快，釋放乾脆俐落。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"四次曲線起步極快，釋放乾脆俐落。\"\n          }\n        }\n      }\n    },\n    \"Waiting for device…\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wag vir toestel…\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"في انتظار الجهاز…\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Čekanje na uređaj…\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"S'està esperant el dispositiu…\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Čekání na zařízení…\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Venter på enhed…\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Warten auf Gerät…\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Αναμονή για συσκευή…\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Esperando el dispositivo…\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Odotetaan laitetta…\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"En attente du périphérique…\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ממתין להתקן…\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Eszközre várakozás…\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Menunggu perangkat…\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"In attesa del dispositivo…\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"デバイスを待機中…\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"기기 대기 중…\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"စက်ပစ္စည်းကို စောင့်နေသည်…\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Venter på enhet…\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wachten op apparaat…\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oczekiwanie na urządzenie…\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aguardando dispositivo…\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Aguardando dispositivo…\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Se așteaptă dispozitivul…\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ожидание устройства…\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Čakanie na zariadenie…\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Чекање на уређај…\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Väntar på enhet…\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cihaz bekleniyor…\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Очікування пристрою…\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Đang chờ thiết bị…\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"等待设备…\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"等待裝置…\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"等待裝置…\"\n          }\n        }\n      }\n    },\n    \"Weekly\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Weekliks\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"أسبوعي\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sedmično\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Setmanal\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Týdně\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ugentligt\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wöchentlich\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Εβδομαδιαία\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Cada semana\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Viikoittain\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Toutes les semaines\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שבועי\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hetente\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mingguan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ogni settimana\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"毎週\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"매주\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အပတ်တိုင်း\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ukentlig\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wekelijks\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Co tydzień\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Semanalmente\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Semanalmente\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Săptămânal\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Еженедельно\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Týždenne\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Недељно\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Veckovis\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Haftalık\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Щотижня\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Hằng tuần\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每周\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每週\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"每週\"\n          }\n        }\n      }\n    },\n    \"When using plain middle click, keep browser-style middle-click behavior on pressable elements instead of entering autoscroll.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Wanneer jy gewone middelkliek gebruik, behou blaaier-styl middelkliek-gedrag op drukbare elemente in plaas daarvan om outo-rol te betree.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"عند استخدام النقر الأوسط العادي، احتفظ بسلوك النقر الأوسط بأسلوب المتصفح على العناصر القابلة للضغط بدلاً من الدخول في التمرير التلقائي.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kada koristite obični klik srednje tipke, zadržite ponašanje klika srednje tipke u stilu preglednika na elementima koji se mogu pritisnuti umjesto ulaska u automatsko pomicanje.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quan utilitzeu el clic central simple, manteniu el comportament de clic central a l'estil del navegador en elements clicables en lloc d'entrar en el desplaçament automàtic.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Při použití běžného prostředního kliknutí zachovejte chování prostředního kliknutí ve stylu prohlížeče na prvcích, na které lze kliknout, místo automatického posouvání.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Når du bruger et almindeligt mellemklik, skal du bevare browser-lignende mellemklik-adfærd på klikbare elementer i stedet for at gå ind i autoscroll.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Verwende bei einfachem Mittelklick das browserähnliche Verhalten für klickbare Elemente anstelle des automatischen Scrollens.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Όταν χρησιμοποιείτε απλό μεσαίο κλικ, διατηρήστε τη συμπεριφορά μεσαίου κλικ τύπου προγράμματος περιήγησης σε στοιχεία που μπορούν να πατηθούν αντί να εισέλθετε σε αυτόματη κύλιση.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Al usar el clic central simple, mantén el comportamiento de clic central estilo navegador en elementos interactivos en lugar de entrar en desplazamiento automático.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Kun käytät tavallista keskinäppäintä, säilytä selaimeen tyypillinen keskinäppäimen toiminta painettavissa olevissa elementeissä sen sijaan, että siirtyisit automaattiseen vieritykseen.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lors de l'utilisation du clic central simple, conservez le comportement de clic central de type navigateur sur les éléments cliquables au lieu d'activer le défilement automatique.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בעת שימוש בלחיצה אמצעית רגילה, שמור על התנהגות לחיצה אמצעית בסגנון דפדפן באלמנטים הניתנים ללחיצה במקום להיכנס לגלילה אוטומטית.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Egyszerű középső kattintás használatakor a kattintható elemek böngészőstílusú középső kattintási viselkedését tartja meg az automatikus görgetés helyett.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saat menggunakan klik tengah biasa, pertahankan perilaku klik tengah gaya browser pada elemen yang dapat ditekan alih-alih masuk ke gulir otomatis.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Quando si utilizza il clic centrale normale, mantieni il comportamento del clic centrale in stile browser sugli elementi cliccabili invece di entrare nello scorrimento automatico.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"通常のミドルクリックを使用する場合、自動スクロールに入る代わりに、クリック可能な要素でブラウザスタイルのミドルクリック動作を維持します。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"일반 중간 클릭을 사용할 때 자동 스크롤로 들어가는 대신 클릭 가능한 요소에서 브라우저 스타일 중간 클릭 동작을 유지합니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"အလယ်ကလစ်ကို အသုံးပြုသည့်အခါ၊ အလိုအလျောက် scroll လုပ်ခြင်းအစား click လုပ်နိုင်သော အရာများပေါ်တွင် browser-style အလယ်ကလစ် အပြုအမူကို ထိန်းသိမ်းပါ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Når du bruker vanlig midtklikk, behold nettleserens midtklikk-atferd på klikkbare elementer i stedet for å aktivere autoskroll.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Houd bij gebruik van een gewone middenklik het gedrag van de middenklik in browserstijl op klikbare elementen in plaats van automatisch scrollen te starten.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podczas używania zwykłego środkowego kliknięcia zachowaj przeglądarkowe zachowanie środkowego kliknięcia na elementach klikalnych zamiast wchodzić w tryb przewijania automatycznego.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ao usar clique do meio simples, mantenha o comportamento de clique do meio no estilo do navegador em elementos clicáveis em vez de entrar na rolagem automática.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ao usar o clique do meio simples, mantenha o comportamento de clique do meio no estilo do navegador em elementos clicáveis em vez de entrar na rolagem automática.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Când utilizați clic de mijloc simplu, păstrați comportamentul de clic de mijloc în stil browser pe elementele care pot fi apăsate, în loc să intrați în derulare automată.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"При использовании обычного среднего клика сохраняйте поведение среднего клика в стиле браузера на интерактивных элементах вместо перехода в режим автопрокрутки.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pri použití bežného stredného kliknutia zachovajte správanie stredného kliknutia v štýle prehliadača na prvkoch, na ktoré sa dá kliknúť, namiesto vstupu do automatického posúvania.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Када користите обичан средњи клик, задржите понашање средњег клика у стилу прегледача на елементима на које се може кликнути уместо уласка у аутоматско скроловање.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"När du använder vanligt mittenklick, behåll webbläsarstilens mittenklicksbeteende på klickbara element istället för att aktivera autoskrollning.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Düz orta tıklama kullanırken, otomatik kaydırmaya girmek yerine tıklanabilir öğelerde tarayıcı tarzı orta tıklama davranışını koruyun.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Під час використання звичайного середнього клацання зберігайте поведінку середнього клацання в стилі браузера на натискних елементах замість автоматичного прокручування.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khi sử dụng nhấp chuột giữa thông thường, giữ nguyên hành vi nhấp chuột giữa kiểu trình duyệt trên các phần tử có thể nhấp thay vì vào chế độ tự động cuộn.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用纯中间键单击时，在可按元素上保留浏览器风格的中间键单击行为，而不是进入自动滚动。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用純中間點擊時，在可按元素上保留瀏覽器風格的中間點擊行為，而非進入自動捲動。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"使用純中間點擊時，請在可按元素上保留瀏覽器風格的中間點擊行為，而非進入自動捲動。\"\n          }\n        }\n      }\n    },\n    \"While pressed\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tydens druk\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"أثناء الضغط\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dok je pritisnut\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mentre està premut\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Při stisknutí\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mens trykket\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Während gedrückt\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Όσο πατιέται\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mientras se mantiene pulsado\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Painettuna\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pendant l’appui\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"בעת לחיצה\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Lenyomás közben\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Saat ditekan\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mentre premuto\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"押している間\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"누르고 있는 동안\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ဖိထားစဉ်\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Mens trykket\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Tijdens indrukken\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Podczas naciskania\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enquanto premido\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Enquanto pressionado\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"În timpul apăsării\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Пока нажато\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Počas stlačenia\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Док је притиснут\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"När nedtryckt\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Basılı tutarken\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Поки натиснуто\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Khi đang nhấn\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住时\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住時\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"按住時\"\n          }\n        }\n      }\n    },\n    \"You may also press ⌃⇧⌘Z to revert to system defaults.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jy kan ook ⌃⇧⌘Z druk om na stelselverstekings terug te keer.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"يمكنك أيضًا الضغط على ⌃⇧⌘Z للعودة إلى إعدادات النظام الافتراضية.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Možete pritisnuti ⌃⇧⌘Z da biste se vratili na tvorničke postavke.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"També podeu prémer ⌃⇧⌘Z per tornar als valors predeterminats del sistema.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Pro obnovení výchozího nastavení systému můžete také použít klávesovou zkratku ⌃⇧⌘Z\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Du kan også trykke på ⌃⇧⌘Z for at vende tilbage til systemets standardindstillinger.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Durch Drücken des Kürzels ⌃⇧⌘Z kann ebenfalls zu den Systemstandards zurückgekehrt werden.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μπορείτε επίσης να πιέσετε ⌃⇧⌘Z για να επανέλθετε στις προεπιλογές του συστήματος.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"También puedes pulsar ⌃⇧⌘Z para restablecer valores por defecto.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Voit myös palauttaa järjestelmän oletusasetukset painamalla ⌃⇧⌘Z.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vous pouvez aussi appuyer sur ⌃⇧⌘Z pour réinitialiser aux paramètres par défauts du système.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"ניתן גם ללחוץ ⌃⇧⌘Z כדי לחזור לברירת המחדל של המערכת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nyomja meg a ⌃⇧⌘Z billentyűkombinációt is a rendszer alapértékeihez való visszaállításhoz.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anda juga dapat menekan ⌃⇧⌘Z untuk mengembalikan ke bawaan sistem.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Puoi anche premere ⌃⇧⌘Z per ripristinare le impostazioni predefinite.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"<unk> ⌘Z を押してデフォルトに戻れます。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃⇧⌘Z를 눌러 시스템 기본값으로 되돌릴 수도 있습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"စနစ်မူလ setting သို့ ပြန်သွားရန် ⌃⇧⌘Z ကိုလည်း နှိပ်နိုင်ပါသည်။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Du kan også trykke ⌃⇧⌘Z for å tilbakestille til systemstandarder.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Je kunt ook ⌃⇧⌘Z indrukken om terug te keren naar de standaard systeeminstellingen.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Możesz także nacisnąć ⌃⇧⌘Z, aby przywrócić ustawienia systemowe.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Também pode premir ⌃⇧⌘Z para restaurar as predefinições do sistema.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Você também pode pressionar ⌃⇧⌘Z para restaurar os padrões.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Puteți, de asemenea, să apăsați ⌃⇧⌘Z pentru a reveni la valorile implicite ale sistemului.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вы также можете нажать ⌃⇧⌘Z, чтобы вернуться к настройкам по умолчанию.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Môžete tiež stlačiť ⌃⇧⌘Z pre návrat k predvoleným nastaveniam systému.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Такође можете притиснути ⌃⇧⌘Z да бисте вратили на фабричка подешавања.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Du kan också trycka på ⌃⇧⌘Z för att återgå till systemstandarder.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"⌃⇧⌘Z'a basarak da fabrika ayarlarına dönebilirsiniz.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ви також можете натиснути ⌃⇧⌘Z, щоб скинути налаштування до стандартних.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bạn có thể ấn ⌃⇧⌘Z để khôi phục hệ thống mặc định.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你也可以按下 ⌃⇧⌘Z 来回退到系统默认值。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你也可以按下 ⌃⇧⌘Z 來回退到系統預設值。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你也可以按下 ⌃⇧⌘Z 來恢復到系統預設值。\"\n          }\n        }\n      }\n    },\n    \"You need to grant Accessibility permission in System Settings > Security & Privacy > Accessibility.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jy moet toeganklikheid toestemming verleen in Stelsel instellings > Sekuriteit en Privaatheid > Toeganklikheid.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تحتاج إلى منح إذن الوصول في إعدادات النظام > الأمان والخصوصية > إمكانية الوصول.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Morate dati dozvolu za Pristupačnost u Postavkama sistema > Sigurnost i privatnost > Pristupačnost.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Heu de concedir el permís d'Accessibilitat a Configuració del sistema > Seguretat i privadesa > Accessibilitat.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Musíte povolit práva Zpřístupnění v Nastavení systému > Soukromí & Zabezpečení > Zpřístupnění.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Du skal give tilladelse til Tilgængelighed i Systemindstillinger… > Anonymitet & sikkerhed > Tilgængelighed.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Erlaube den Zugriff auf die Bedienungshilfen über die Systemeinstellungen > Sicherheit & Datenschutz > Bedienungshilfen.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Πρέπει να παραχωρήσετε δικαιώματα προσβασιμότητας στις Ρυθμίσεις Συστήματος > Ασφάλεια & Απόρρητο > Προσβασιμότητα.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Necesitas conceder permiso de Accesibilidad en Preferencias del sistema > Seguridad y privacidad > Accesibilidad.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sinun on myönnettävä esteettömyyskäyttöoikeus kohdassa Järjestelmäasetukset > Suojaus ja yksityisyys > Esteettömyys.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vous devez accorder l’autorisation d’accessibilité dans Paramètres système > Sécurité et confidentialité > Accessibilité.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"יש לתת השראות נגישות תחת ״הגדרות המערכת״ > ״פרטיות ואבטחה״ > ״נגישות״.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Engedélyeznie kell a Kisegítő lehetőségek hozzáférést a Rendszerbeállítások > Biztonság és adatvédelem > Kisegítő lehetőségek menüpontban.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Anda perlu memberikan izin Aksesibilitas di Pengaturan Sistem > Keamanan & Privasi > Aksesibilitas.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Devi concedere il permesso di Accessibilità nelle Impostazioni di Sistema > Sicurezza e Privacy > Accessibilità.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"システム環境設定 > セキュリティ & プライバシー > アクセシビリティで、Linear Mouseのアクセシビリティの許可が必要です。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"시스템 설정 > 개인정보 보호 및 보안 > 손쉬운 사용에서 이 응용 프로그램에 접근 권한을 부여하십시오.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"System Settings > Security & Privacy > Accessibility တွင် Accessibility permission ကိုခွင့်ပြုပေးရန် လိုအပ်ပါသည်။.\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Du må gi Tilgjengelighets-tillatelse i Systeminnstillinger > Sikkerhet og personvern > Tilgjengelighet.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"U moet toegangsrechten verlenen in Systeeminstellingen > Beveiliging & Privacy > Toegankelijkheid.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Musisz nam przyznać uprawnienia Dostępności poprzez Ustawienia Systemowe > Prywatność i ochrona > Dostępność.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Precisa de conceder permissão de acessibilidade em Definições do Sistema > Privacidade e segurança > Acessibilidade.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Você precisa conceder permissão de acessibilidade em Configurações do Sistema > Segurança & Privacidade > Acessibilidade.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Trebuie să acordați permisiunea de accesibilitate în Setările de sistem > Securitate & Confidențialitate > Accesibilitate.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вам необходимо предоставить разрешение на Универсальный доступ. Перейдите в Системные настройки > Конфиденциальность и безопасность > Универсальный доступ.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Oprávnenie na Prístupnosť musíte udeliť v časti Systémové Nastavenia > Súkromie a bezpečnosť > Prístupnosť.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Морате да доделите дозволу за Приступачност у Поставкама система > Безбедност и приватност > Приступачност.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Du måste bevilja tillstånd för tillgänglighet i Systeminställningar > Säkerhet och sekretess > Tillgänglighet.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sistem Ayarları > Gizlilik & Güvenlik > Erişilebilirlik üzerinden Erişilebilirlik izni vermeniz gerekiyor.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Вам потрібно надати дозвіл на доступ до спеціальних можливостей в Налаштуваннях > Безпека та Конфіденційність > Доступність.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Bạn cần phải cấp quyền truy cập Trợ năng trong Cài đặt -> Quyền riêng tư & Bảo mật -> Trợ năng.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你需要在系统设置 > 安全性与隐私 > 辅助功能中授予辅助功能权限。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你需要在系統設定 > 安全性與隱私權 > 輔助使用中授予輔助使用權限。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你需要在系統設定 > 保安與私隱 > 輔助使用中授予輔助使用權限。\"\n          }\n        }\n      }\n    },\n    \"Your configuration changes are now active.\" : {\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Jou konfigurasieveranderings is nou aktief.\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تغييرات التكوين الخاصة بك نشطة الآن.\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vaše promjene konfiguracije su sada aktivne.\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Els canvis de configuració ara estan actius.\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Změny konfigurace jsou nyní aktivní.\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dine konfigurationsændringer er nu aktive.\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Deine Konfigurationsänderungen sind jetzt aktiv.\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Οι αλλαγές στη διαμόρφωσή σας είναι πλέον ενεργές.\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Sus cambios en la configuración están ahora activos.\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Määrityksesi muutokset ovat nyt aktiivisia.\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vos modifications de configuration sont maintenant actives.\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"שינויי התצורה שלך פעילים כעת.\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"A konfigurációs módosítások most aktívak.\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Perubahan konfigurasi Anda kini aktif.\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Le modifiche alla configurazione sono ora attive.\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"設定の変更が適用されました。\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"설정 변경 사항이 활성화되었습니다.\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"သင့်၏ ဖွဲ့စည်းပုံ ပြောင်းလဲမှုများ ယခု အသက်ဝင်နေပါပြီ။\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Konfigurasjonsendringene dine er nå aktive.\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Uw configuratiewijzigingen zijn nu actief.\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zmiany konfiguracji są teraz aktywne.\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"As suas alterações de configuração estão agora ativas.\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Suas alterações de configuração agora estão ativas.\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Modificările de configurare sunt acum active.\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Изменения вашей конфигурации теперь активны.\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Vaše zmeny konfigurácie sú teraz aktívne.\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ваше промене конфигурације су сада активне.\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Dina konfigurationsändringar är nu aktiva.\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yapılandırma değişiklikleriniz artık aktif.\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зміни вашої конфігурації тепер активні.\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Các thay đổi cấu hình của bạn hiện đã có hiệu lực.\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"你的配置更改现已生效。\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"您的設定變更現已生效。\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"您的設定變更現已生效。\"\n          }\n        }\n      }\n    },\n    \"Zoom\" : {\n      \"extractionState\" : \"manual\",\n      \"localizations\" : {\n        \"af\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoem\"\n          }\n        },\n        \"ar\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"تكبير/تصغير\"\n          }\n        },\n        \"bs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zumiranje\"\n          }\n        },\n        \"ca\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"cs\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Přiblížit\"\n          }\n        },\n        \"da\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"de\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"el\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Μεγέθυνση\"\n          }\n        },\n        \"en\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"es\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"fi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoomaus\"\n          }\n        },\n        \"fr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"he\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"הגדל/הקטן\"\n          }\n        },\n        \"hu\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Nagyítás\"\n          }\n        },\n        \"id\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"it\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ingrandimento\"\n          }\n        },\n        \"ja\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"拡大\"\n          }\n        },\n        \"ko\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"확대\"\n          }\n        },\n        \"my\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"nb-NO\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"nl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"pl\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Powiększanie\"\n          }\n        },\n        \"pt\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Ampliação\"\n          }\n        },\n        \"pt-BR\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"ro\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"ru\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Масштабирование\"\n          }\n        },\n        \"sk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zväčšiť\"\n          }\n        },\n        \"sr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Зум\"\n          }\n        },\n        \"sv\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Zoom\"\n          }\n        },\n        \"tr\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Yakınlaştır\"\n          }\n        },\n        \"uk\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Масштабування\"\n          }\n        },\n        \"vi\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"Thu phóng\"\n          }\n        },\n        \"zh-Hans\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"缩放\"\n          }\n        },\n        \"zh-Hant\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"縮放\"\n          }\n        },\n        \"zh-Hant-HK\" : {\n          \"stringUnit\" : {\n            \"state\" : \"translated\",\n            \"value\" : \"縮放\"\n          }\n        }\n      }\n    }\n  },\n  \"version\" : \"1.1\"\n}"
  },
  {
    "path": "LinearMouse/Model/AppTarget.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nenum AppTarget: Hashable {\n    case bundle(String)\n    case executable(String)\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Configuration.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Defaults\nimport Foundation\nimport JSONPatcher\n\nstruct Configuration: Codable, Equatable {\n    let jsonSchema = \"https://schema.linearmouse.app/\\(LinearMouse.appVersion)\"\n\n    var schemes: [Scheme] = []\n\n    enum CodingKeys: String, CodingKey {\n        case jsonSchema = \"$schema\"\n        case schemes\n    }\n\n    enum ConfigurationError: Error {\n        case unsupportedEncoding\n        case parseError(Error)\n    }\n}\n\nextension Configuration.ConfigurationError: LocalizedError {\n    var errorDescription: String? {\n        switch self {\n        case .unsupportedEncoding:\n            return NSLocalizedString(\"Unsupported encoding, expected UTF-8\", comment: \"\")\n        case let .parseError(underlyingError):\n            if let decodingError = underlyingError as? DecodingError {\n                switch decodingError {\n                case let .typeMismatch(type, context):\n                    return String(\n                        format: NSLocalizedString(\"Type mismatch: expected %1$@ at %2$@\", comment: \"\"),\n                        String(describing: type),\n                        String(describing: context.codingPath.map(\\.stringValue).joined(separator: \".\"))\n                    )\n                case let .keyNotFound(codingKey, context):\n                    return String(\n                        format: NSLocalizedString(\"Missing key %1$@ at %2$@\", comment: \"\"),\n                        String(describing: codingKey.stringValue),\n                        String(describing: context.codingPath.map(\\.stringValue).joined(separator: \".\"))\n                    )\n                default:\n                    break\n                }\n                return String(describing: underlyingError)\n            }\n            // TODO: More detailed description in underlyingError.\n            return String(\n                format: NSLocalizedString(\"Invalid JSON: %@\", comment: \"\"),\n                underlyingError.localizedDescription\n            )\n        }\n    }\n}\n\nextension Configuration {\n    static func load(from string: String) throws -> Configuration {\n        do {\n            let jsonPatcher = try JSONPatcher(original: string)\n            let json = jsonPatcher.json()\n            guard let data = json.data(using: .utf8) else {\n                throw ConfigurationError.unsupportedEncoding\n            }\n            let decoder = JSONDecoder()\n            return try decoder.decode(Configuration.self, from: data)\n        } catch {\n            throw ConfigurationError.parseError(error)\n        }\n    }\n\n    static func load(from data: Data) throws -> Configuration {\n        guard let string = String(data: data, encoding: .utf8) else {\n            throw ConfigurationError.unsupportedEncoding\n        }\n        return try load(from: string)\n    }\n\n    static func load(from url: URL) throws -> Configuration {\n        try load(from: Data(contentsOf: url))\n    }\n\n    func dump() throws -> Data {\n        let encoder = JSONEncoder()\n\n        encoder.outputFormatting = [.prettyPrinted, .sortedKeys]\n\n        return try encoder.encode(self)\n    }\n\n    func dump(to url: URL) throws {\n        let parentDirectory = url.deletingLastPathComponent()\n        if !FileManager.default.fileExists(atPath: parentDirectory.path) {\n            try FileManager.default.createDirectory(at: parentDirectory, withIntermediateDirectories: true)\n        }\n        try dump().write(to: url.resolvingSymlinksInPath(), options: .atomic)\n    }\n\n    func matchScheme(\n        withDevice device: Device? = nil,\n        withApp app: String? = nil,\n        withParentApp parentApp: String? = nil,\n        withGroupApp groupApp: String? = nil,\n        withDisplay display: String? = nil,\n        withProcessName processName: String? = nil,\n        withProcessPath processPath: String? = nil\n    ) -> Scheme {\n        // TODO: Backtrace the merge path\n        // TODO: Optimize the algorithm\n\n        var mergedScheme = Scheme()\n\n        let `if` = Scheme.If(\n            device: device.map { DeviceMatcher(of: $0) },\n            app: app,\n            parentApp: parentApp,\n            groupApp: groupApp,\n            processName: processName,\n            processPath: processPath,\n            display: display\n        )\n\n        mergedScheme.if = [`if`]\n\n        for scheme in schemes where scheme.isActive(\n            withDevice: device,\n            withApp: app,\n            withParentApp: parentApp,\n            withGroupApp: groupApp,\n            withDisplay: display,\n            withProcessName: processName,\n            withProcessPath: processPath\n        ) {\n            scheme.merge(into: &mergedScheme)\n        }\n\n        return mergedScheme\n    }\n\n    func matchScheme(\n        withDevice device: Device? = nil,\n        withPid pid: pid_t? = nil,\n        withDisplay display: String? = nil\n    ) -> Scheme {\n        matchScheme(\n            withDevice: device,\n            withApp: pid?.bundleIdentifier,\n            withParentApp: pid?.parent?.bundleIdentifier,\n            withGroupApp: pid?.group?.bundleIdentifier,\n            withDisplay: display,\n            withProcessName: pid?.processName,\n            withProcessPath: pid?.processPath\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/DeviceMatcher.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\n\nstruct DeviceMatcher: Codable, Equatable, Hashable, Defaults.Serializable {\n    @HexRepresentation var vendorID: Int?\n    @HexRepresentation var productID: Int?\n    var productName: String?\n    var serialNumber: String?\n    @SingleValueOrArray var category: [Category]?\n\n    enum Category: String, Codable, Hashable {\n        case mouse, trackpad\n    }\n}\n\nextension DeviceMatcher {\n    init(of device: Device) {\n        self.init(\n            vendorID: device.vendorID,\n            productID: device.productID,\n            productName: device.productName,\n            serialNumber: device.serialNumber,\n            category: [Category(from: device.category)]\n        )\n    }\n\n    func match(with device: Device) -> Bool {\n        func matchValue<T: Equatable>(_ destination: T?, _ source: T) -> Bool {\n            destination == nil || source == destination\n        }\n\n        func matchValue<T: Equatable>(_ destination: T?, _ source: T?) -> Bool {\n            destination == nil || source == destination\n        }\n\n        guard matchValue(vendorID, device.vendorID),\n              matchValue(productID, device.productID),\n              matchValue(productName, device.productName),\n              matchValue(serialNumber, device.serialNumber)\n        else {\n            return false\n        }\n\n        if let category {\n            guard category.contains(where: { $0.deviceCategory == device.category }) else {\n                return false\n            }\n        }\n\n        return true\n    }\n}\n\nextension DeviceMatcher.Category {\n    init(from deviceCategory: Device.Category) {\n        switch deviceCategory {\n        case .mouse:\n            self = .mouse\n        case .trackpad:\n            self = .trackpad\n        }\n    }\n\n    var deviceCategory: Device.Category {\n        switch self {\n        case .mouse:\n            return .mouse\n        case .trackpad:\n            return .trackpad\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/AutoScroll/AutoScroll.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme.Buttons {\n    struct AutoScroll: Equatable, ImplicitInitable {\n        enum Mode: String, Codable, Equatable, CaseIterable, Identifiable {\n            var id: Self {\n                self\n            }\n\n            case toggle\n            case hold\n        }\n\n        var enabled: Bool?\n        var modes: [Mode]?\n        var speed: Decimal?\n        var preserveNativeMiddleClick: Bool?\n        var trigger: Mapping?\n\n        init() {}\n    }\n}\n\nextension Scheme.Buttons.AutoScroll: Codable {\n    private enum CodingKeys: String, CodingKey {\n        case enabled\n        case mode\n        case speed\n        case preserveNativeMiddleClick\n        case trigger\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n\n        enabled = try container.decodeIfPresent(Bool.self, forKey: .enabled)\n        modes = try container.decodeIfPresent(SingleValueOrArray<Mode>.self, forKey: .mode)?.wrappedValue\n        speed = try container.decodeIfPresent(Decimal.self, forKey: .speed)\n        preserveNativeMiddleClick = try container.decodeIfPresent(Bool.self, forKey: .preserveNativeMiddleClick)\n        trigger = try container.decodeIfPresent(Scheme.Buttons.Mapping.self, forKey: .trigger)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n\n        try container.encodeIfPresent(enabled, forKey: .enabled)\n        try container.encode(SingleValueOrArray(wrappedValue: modes), forKey: .mode)\n        try container.encodeIfPresent(speed, forKey: .speed)\n        try container.encodeIfPresent(preserveNativeMiddleClick, forKey: .preserveNativeMiddleClick)\n        try container.encodeIfPresent(trigger, forKey: .trigger)\n    }\n}\n\nextension Scheme.Buttons.AutoScroll {\n    var normalizedModes: [Mode] {\n        let orderedModes = Mode.allCases.filter { modes?.contains($0) == true }\n        return orderedModes.isEmpty ? [.toggle] : orderedModes\n    }\n\n    var hasToggleMode: Bool {\n        normalizedModes.contains(.toggle)\n    }\n\n    var hasHoldMode: Bool {\n        normalizedModes.contains(.hold)\n    }\n\n    func merge(into autoScroll: inout Self) {\n        if let enabled {\n            autoScroll.enabled = enabled\n        }\n\n        if let modes {\n            autoScroll.modes = modes\n        }\n\n        if let speed {\n            autoScroll.speed = speed\n        }\n\n        if let preserveNativeMiddleClick {\n            autoScroll.preserveNativeMiddleClick = preserveNativeMiddleClick\n        }\n\n        if let trigger {\n            autoScroll.trigger = trigger\n        }\n    }\n\n    func merge(into autoScroll: inout Self?) {\n        if autoScroll == nil {\n            autoScroll = Self()\n        }\n\n        merge(into: &autoScroll!)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Buttons.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme {\n    struct Buttons: Codable, Equatable, ImplicitInitable {\n        var mappings: [Mapping]?\n\n        enum UniversalBackForward {\n            case none\n            case both\n            case backOnly\n            case forwardOnly\n        }\n\n        var universalBackForward: UniversalBackForward?\n\n        var switchPrimaryButtonAndSecondaryButtons: Bool?\n\n        @ImplicitOptional var clickDebouncing: ClickDebouncing\n\n        @ImplicitOptional var autoScroll: AutoScroll\n\n        @ImplicitOptional var gesture: Gesture\n    }\n}\n\nextension Scheme.Buttons {\n    func merge(into buttons: inout Self) {\n        if let mappings, !mappings.isEmpty {\n            buttons.mappings = (buttons.mappings ?? []) + mappings\n        }\n\n        if let universalBackForward {\n            buttons.universalBackForward = universalBackForward\n        }\n\n        if let switchPrimaryButtonAndSecondaryButtons {\n            buttons.switchPrimaryButtonAndSecondaryButtons = switchPrimaryButtonAndSecondaryButtons\n        }\n\n        if let clickDebouncing = $clickDebouncing {\n            buttons.clickDebouncing = clickDebouncing\n        }\n\n        if let autoScroll = $autoScroll {\n            autoScroll.merge(into: &buttons.$autoScroll)\n        }\n\n        if let gesture = $gesture {\n            buttons.$gesture = gesture\n        }\n    }\n\n    func merge(into buttons: inout Self?) {\n        if buttons == nil {\n            buttons = Self()\n        }\n\n        merge(into: &buttons!)\n    }\n}\n\nextension Scheme.Buttons.UniversalBackForward: Codable {\n    enum ValueError: Error {\n        case invalidValue\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n\n        do {\n            self = try container.decode(Bool.self) ? .both : .none\n        } catch {\n            switch try container.decode(String.self) {\n            case \"backOnly\":\n                self = .backOnly\n            case \"forwardOnly\":\n                self = .forwardOnly\n            default:\n                throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n            }\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n\n        switch self {\n        case .none:\n            try container.encode(false)\n        case .both:\n            try container.encode(true)\n        case .backOnly:\n            try container.encode(\"backOnly\")\n        case .forwardOnly:\n            try container.encode(\"forwardOnly\")\n        }\n    }\n}\n\nextension Scheme.Buttons.UniversalBackForward.ValueError: LocalizedError {\n    var errorDescription: String? {\n        switch self {\n        case .invalidValue:\n            return NSLocalizedString(\n                \"UniversalBackForward must be true, false, \\\"backOnly\\\" or \\\"forwardOnly\\\"\",\n                comment: \"\"\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/ClickDebouncing/ClickDebouncing.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Scheme.Buttons {\n    struct ClickDebouncing: Codable, Equatable, ImplicitInitable {\n        var timeout: Int?\n        var resetTimerOnMouseUp: Bool?\n        var buttons: [CGMouseButton]?\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Gesture/Gesture.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme.Buttons {\n    struct Gesture: Equatable, ImplicitInitable {\n        var enabled: Bool?\n        var trigger: Mapping?\n        var threshold: Int?\n        var deadZone: Int?\n        var cooldownMs: Int?\n\n        @ImplicitOptional var actions: Actions\n\n        struct Actions: Codable, Equatable, ImplicitInitable {\n            var left: GestureAction?\n            var right: GestureAction?\n            var up: GestureAction?\n            var down: GestureAction?\n        }\n\n        enum GestureAction: String, Codable, Equatable, Hashable, Identifiable, CaseIterable {\n            var id: Self {\n                self\n            }\n\n            case none\n            case spaceLeft = \"missionControl.spaceLeft\"\n            case spaceRight = \"missionControl.spaceRight\"\n            case missionControl\n            case appExpose\n            case showDesktop\n            case launchpad\n        }\n    }\n}\n\nextension Scheme.Buttons.Gesture: Codable {\n    private enum CodingKeys: String, CodingKey {\n        case enabled\n        case trigger\n        case button\n        case threshold\n        case deadZone\n        case cooldownMs\n        case actions\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        enabled = try container.decodeIfPresent(Bool.self, forKey: .enabled)\n        trigger = try container.decodeIfPresent(Scheme.Buttons.Mapping.self, forKey: .trigger)\n        threshold = try container.decodeIfPresent(Int.self, forKey: .threshold)\n        deadZone = try container.decodeIfPresent(Int.self, forKey: .deadZone)\n        cooldownMs = try container.decodeIfPresent(Int.self, forKey: .cooldownMs)\n        _actions = try container.decodeIfPresent(ImplicitOptional<Actions>.self, forKey: .actions) ?? .init()\n\n        // Migrate legacy \"button\" field to \"trigger\"\n        if trigger == nil, let button = try container.decodeIfPresent(Int.self, forKey: .button) {\n            var mapping = Scheme.Buttons.Mapping()\n            mapping.button = .mouse(button)\n            trigger = mapping\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encodeIfPresent(enabled, forKey: .enabled)\n        try container.encodeIfPresent(trigger, forKey: .trigger)\n        try container.encodeIfPresent(threshold, forKey: .threshold)\n        try container.encodeIfPresent(deadZone, forKey: .deadZone)\n        try container.encodeIfPresent(cooldownMs, forKey: .cooldownMs)\n        try container.encodeIfPresent($actions, forKey: .actions)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Mapping/Action+Codable.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport KeyKit\n\nextension Scheme.Buttons.Mapping.Action: Codable {\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n\n        if let value = try? container.decode(Arg0.self) {\n            self = .arg0(value)\n            return\n        }\n\n        if let value = try? container.decode(Arg1.self) {\n            self = .arg1(value)\n            return\n        }\n\n        self = .arg0(.auto)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n\n        switch self {\n        case let .arg0(value):\n            try container.encode(value)\n\n        case let .arg1(value):\n            try container.encode(value)\n        }\n    }\n}\n\nextension Scheme.Buttons.Mapping.Action.Arg1: Codable {\n    enum CodingKeys: String, CodingKey {\n        case run\n\n        case mouseWheelScrollUp = \"mouse.wheel.scrollUp\"\n        case mouseWheelScrollDown = \"mouse.wheel.scrollDown\"\n        case mouseWheelScrollLeft = \"mouse.wheel.scrollLeft\"\n        case mouseWheelScrollRight = \"mouse.wheel.scrollRight\"\n        case keyPress\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n\n        if let command = try? container.decode(String.self, forKey: .run) {\n            self = .run(command)\n            return\n        }\n\n        if let distance = try? container.decode(Scheme.Scrolling.Distance.self, forKey: .mouseWheelScrollUp) {\n            self = .mouseWheelScrollUp(distance)\n            return\n        }\n\n        if let distance = try? container.decode(Scheme.Scrolling.Distance.self, forKey: .mouseWheelScrollDown) {\n            self = .mouseWheelScrollDown(distance)\n            return\n        }\n\n        if let distance = try? container.decode(Scheme.Scrolling.Distance.self, forKey: .mouseWheelScrollLeft) {\n            self = .mouseWheelScrollLeft(distance)\n            return\n        }\n\n        if let distance = try? container.decode(Scheme.Scrolling.Distance.self, forKey: .mouseWheelScrollRight) {\n            self = .mouseWheelScrollRight(distance)\n            return\n        }\n\n        if let keys = try? container.decode([Key].self, forKey: .keyPress) {\n            self = .keyPress(keys)\n            return\n        }\n\n        throw CustomDecodingError(in: container, error: DecodingError.invalidValue)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        switch self {\n        case let .run(command):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(command, forKey: .run)\n\n        case let .mouseWheelScrollUp(distance):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(distance, forKey: .mouseWheelScrollUp)\n\n        case let .mouseWheelScrollDown(distance):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(distance, forKey: .mouseWheelScrollDown)\n\n        case let .mouseWheelScrollLeft(distance):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(distance, forKey: .mouseWheelScrollLeft)\n\n        case let .mouseWheelScrollRight(distance):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(distance, forKey: .mouseWheelScrollRight)\n\n        case let .keyPress(keys):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(keys, forKey: .keyPress)\n        }\n    }\n\n    enum DecodingError: Error {\n        case invalidValue\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Mapping/Action+CustomStringConvertible.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme.Buttons.Mapping.Action: CustomStringConvertible {\n    var description: String {\n        switch self {\n        case let .arg0(value):\n            return value.description\n        case let .arg1(value):\n            return value.description\n        }\n    }\n}\n\nextension Scheme.Buttons.Mapping.Action.Arg0: CustomStringConvertible {\n    var description: String {\n        switch self {\n        case .auto:\n            return NSLocalizedString(\"Default action\", comment: \"\")\n        case .none:\n            return NSLocalizedString(\"No action\", comment: \"\")\n        case .missionControl:\n            return NSLocalizedString(\"Mission Control\", comment: \"\")\n        case .missionControlSpaceLeft:\n            return NSLocalizedString(\"Move left a space\", comment: \"\")\n        case .missionControlSpaceRight:\n            return NSLocalizedString(\"Move right a space\", comment: \"\")\n        case .appExpose:\n            return NSLocalizedString(\"Application windows\", comment: \"\")\n        case .launchpad:\n            return NSLocalizedString(\"Launchpad\", comment: \"\")\n        case .showDesktop:\n            return NSLocalizedString(\"Show desktop\", comment: \"\")\n        case .lookUpAndDataDetectors:\n            return NSLocalizedString(\"Look up & data detectors\", comment: \"\")\n        case .smartZoom:\n            return NSLocalizedString(\"Smart zoom\", comment: \"\")\n        case .displayBrightnessUp:\n            return NSLocalizedString(\"Increase display brightness\", comment: \"\")\n        case .displayBrightnessDown:\n            return NSLocalizedString(\"Decrease display brightness\", comment: \"\")\n        case .mediaVolumeUp:\n            return NSLocalizedString(\"Increase volume\", comment: \"\")\n        case .mediaVolumeDown:\n            return NSLocalizedString(\"Decrease volume\", comment: \"\")\n        case .mediaMute:\n            return NSLocalizedString(\"Mute / unmute\", comment: \"\")\n        case .mediaPlayPause:\n            return NSLocalizedString(\"Play / pause\", comment: \"\")\n        case .mediaNext:\n            return NSLocalizedString(\"Next\", comment: \"\")\n        case .mediaPrevious:\n            return NSLocalizedString(\"Previous\", comment: \"\")\n        case .mediaFastForward:\n            return NSLocalizedString(\"Fast forward\", comment: \"\")\n        case .mediaRewind:\n            return NSLocalizedString(\"Rewind\", comment: \"\")\n        case .keyboardBrightnessUp:\n            return NSLocalizedString(\"Increase keyboard brightness\", comment: \"\")\n        case .keyboardBrightnessDown:\n            return NSLocalizedString(\"Decrease keyboard brightness\", comment: \"\")\n        case .mouseWheelScrollUp:\n            return NSLocalizedString(\"Scroll up\", comment: \"\")\n        case .mouseWheelScrollDown:\n            return NSLocalizedString(\"Scroll down\", comment: \"\")\n        case .mouseWheelScrollLeft:\n            return NSLocalizedString(\"Scroll left\", comment: \"\")\n        case .mouseWheelScrollRight:\n            return NSLocalizedString(\"Scroll right\", comment: \"\")\n        case .mouseButtonLeft:\n            return NSLocalizedString(\"Primary click\", comment: \"\")\n        case .mouseButtonLeftDouble:\n            return NSLocalizedString(\"Primary double-click\", comment: \"\")\n        case .mouseButtonMiddle:\n            return NSLocalizedString(\"Middle click\", comment: \"\")\n        case .mouseButtonRight:\n            return NSLocalizedString(\"Secondary click\", comment: \"\")\n        case .mouseButtonBack:\n            return NSLocalizedString(\"Back\", comment: \"\")\n        case .mouseButtonForward:\n            return NSLocalizedString(\"Forward\", comment: \"\")\n        }\n    }\n}\n\nextension Scheme.Buttons.Mapping.Action.Arg1: CustomStringConvertible {\n    var description: String {\n        switch self {\n        case let .run(command):\n            return String(format: NSLocalizedString(\"Run: %@\", comment: \"\"), command)\n        case let .mouseWheelScrollUp(distance):\n            return String(format: NSLocalizedString(\"Scroll up %@\", comment: \"\"), String(describing: distance))\n        case let .mouseWheelScrollDown(distance):\n            return String(format: NSLocalizedString(\"Scroll down %@\", comment: \"\"), String(describing: distance))\n        case let .mouseWheelScrollLeft(distance):\n            return String(format: NSLocalizedString(\"Scroll left %@\", comment: \"\"), String(describing: distance))\n        case let .mouseWheelScrollRight(distance):\n            return String(format: NSLocalizedString(\"Scroll right %@\", comment: \"\"), String(describing: distance))\n        case let .keyPress(keys):\n            return String(\n                format: NSLocalizedString(\"Keyboard shortcut: %@\", comment: \"\"),\n                keys.map(\\.description).joined()\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Mapping/Action+Kind.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Scheme.Buttons.Mapping.Action {\n    enum Kind: Equatable, Hashable {\n        case arg0(Arg0)\n        case run\n        case mouseWheelScrollUp\n        case mouseWheelScrollDown\n        case mouseWheelScrollLeft\n        case mouseWheelScrollRight\n        case keyPress\n    }\n\n    var kind: Kind {\n        switch self {\n        case let .arg0(value):\n            return .arg0(value)\n        case .arg1(.run):\n            return .run\n        case .arg1(.mouseWheelScrollUp):\n            return .mouseWheelScrollUp\n        case .arg1(.mouseWheelScrollDown):\n            return .mouseWheelScrollDown\n        case .arg1(.mouseWheelScrollLeft):\n            return .mouseWheelScrollLeft\n        case .arg1(.mouseWheelScrollRight):\n            return .mouseWheelScrollRight\n        case .arg1(.keyPress):\n            return .keyPress\n        }\n    }\n\n    init(kind: Kind) {\n        switch kind {\n        case let .arg0(value):\n            self = .arg0(value)\n        case .run:\n            self = .arg1(.run(\"\"))\n        case .mouseWheelScrollUp:\n            self = .arg1(.mouseWheelScrollUp(.line(3)))\n        case .mouseWheelScrollDown:\n            self = .arg1(.mouseWheelScrollDown(.line(3)))\n        case .mouseWheelScrollLeft:\n            self = .arg1(.mouseWheelScrollLeft(.line(3)))\n        case .mouseWheelScrollRight:\n            self = .arg1(.mouseWheelScrollRight(.line(3)))\n        case .keyPress:\n            self = .arg1(.keyPress([]))\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Mapping/Action.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport KeyKit\n\nextension Scheme.Buttons.Mapping {\n    // TODO: Refactor enum with protocol.\n    enum Action: Equatable, Hashable {\n        case arg0(Arg0)\n        case arg1(Arg1)\n    }\n}\n\nextension Scheme.Buttons.Mapping.Action {\n    enum Arg0: String, Codable, Identifiable, CaseIterable {\n        var id: Self {\n            self\n        }\n\n        case auto\n        case none\n\n        case missionControl\n        case missionControlSpaceLeft = \"missionControl.spaceLeft\"\n        case missionControlSpaceRight = \"missionControl.spaceRight\"\n\n        case appExpose\n        case launchpad\n        case showDesktop\n        case lookUpAndDataDetectors\n        case smartZoom\n\n        case displayBrightnessUp = \"display.brightnessUp\"\n        case displayBrightnessDown = \"display.brightnessDown\"\n\n        case mediaVolumeUp = \"media.volumeUp\"\n        case mediaVolumeDown = \"media.volumeDown\"\n        case mediaMute = \"media.mute\"\n        case mediaPlayPause = \"media.playPause\"\n        case mediaNext = \"media.next\"\n        case mediaPrevious = \"media.previous\"\n        case mediaFastForward = \"media.fastForward\"\n        case mediaRewind = \"media.rewind\"\n\n        case keyboardBrightnessUp = \"keyboard.brightnessUp\"\n        case keyboardBrightnessDown = \"keyboard.brightnessDown\"\n\n        case mouseWheelScrollUp = \"mouse.wheel.scrollUp\"\n        case mouseWheelScrollDown = \"mouse.wheel.scrollDown\"\n        case mouseWheelScrollLeft = \"mouse.wheel.scrollLeft\"\n        case mouseWheelScrollRight = \"mouse.wheel.scrollRight\"\n\n        case mouseButtonLeft = \"mouse.button.left\"\n        case mouseButtonLeftDouble = \"mouse.button.leftDouble\"\n        case mouseButtonMiddle = \"mouse.button.middle\"\n        case mouseButtonRight = \"mouse.button.right\"\n        case mouseButtonBack = \"mouse.button.back\"\n        case mouseButtonForward = \"mouse.button.forward\"\n    }\n\n    enum Arg1: Equatable, Hashable {\n        case run(String)\n\n        case mouseWheelScrollUp(Scheme.Scrolling.Distance)\n        case mouseWheelScrollDown(Scheme.Scrolling.Distance)\n        case mouseWheelScrollLeft(Scheme.Scrolling.Distance)\n        case mouseWheelScrollRight(Scheme.Scrolling.Distance)\n\n        case keyPress([Key])\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Buttons/Mapping/Mapping.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Scheme.Buttons {\n    struct Mapping: Equatable, Hashable {\n        var button: Button?\n        var `repeat`: Bool?\n        var hold: Bool?\n\n        var scroll: ScrollDirection?\n\n        var command: Bool?\n        var shift: Bool?\n        var option: Bool?\n        var control: Bool?\n\n        var action: Action?\n    }\n}\n\nextension Scheme.Buttons.Mapping {\n    enum Button: Equatable, Hashable {\n        case mouse(Int)\n        case logitechControl(LogitechControlIdentity)\n\n        var mouseButtonNumber: Int? {\n            guard case let .mouse(buttonNumber) = self else {\n                return nil\n            }\n\n            return buttonNumber\n        }\n\n        var logitechControl: LogitechControlIdentity? {\n            guard case let .logitechControl(identity) = self else {\n                return nil\n            }\n\n            return identity\n        }\n\n        var syntheticMouseButtonNumber: Int {\n            switch self {\n            case let .mouse(buttonNumber):\n                return buttonNumber\n            case .logitechControl:\n                return LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.reservedVirtualButtonNumber\n            }\n        }\n    }\n\n    var valid: Bool {\n        guard button != nil || scroll != nil else {\n            return false\n        }\n\n        guard !(button?.mouseButtonNumber == 0 && modifierFlags.isEmpty) else {\n            return false\n        }\n\n        return true\n    }\n\n    enum ScrollDirection: String, Codable, Hashable {\n        case up, down, left, right\n    }\n\n    enum KeyPressBehavior: String, CaseIterable, Identifiable {\n        case sendOnRelease\n        case `repeat`\n        case holdWhilePressed\n\n        var id: Self {\n            self\n        }\n    }\n\n    var keyPressBehavior: KeyPressBehavior {\n        get {\n            if hold == true {\n                return .holdWhilePressed\n            }\n\n            if `repeat` == true {\n                return .repeat\n            }\n\n            return .sendOnRelease\n        }\n        set {\n            switch newValue {\n            case .sendOnRelease:\n                `repeat` = nil\n                hold = nil\n            case .repeat:\n                `repeat` = true\n                hold = nil\n            case .holdWhilePressed:\n                `repeat` = nil\n                hold = true\n            }\n        }\n    }\n\n    var modifierFlags: CGEventFlags {\n        get {\n            CGEventFlags([\n                (command, CGEventFlags.maskCommand),\n                (shift, CGEventFlags.maskShift),\n                (option, CGEventFlags.maskAlternate),\n                (control, CGEventFlags.maskControl)\n            ]\n            .filter { $0.0 == true }\n            .map(\\.1)\n            )\n        }\n\n        set {\n            let genericFlags = ModifierState.generic(from: newValue)\n            command = genericFlags.contains(.maskCommand)\n            shift = genericFlags.contains(.maskShift)\n            option = genericFlags.contains(.maskAlternate)\n            control = genericFlags.contains(.maskControl)\n        }\n    }\n\n    func match(with event: CGEvent) -> Bool {\n        guard matches(modifierFlags: event.flags) else {\n            return false\n        }\n\n        if let mouseButtonNumber = button?.mouseButtonNumber {\n            guard [.leftMouseDown, .leftMouseUp, .leftMouseDragged,\n                   .rightMouseDown, .rightMouseUp, .rightMouseDragged,\n                   .otherMouseDown, .otherMouseUp, .otherMouseDragged].contains(event.type) else {\n                return false\n            }\n\n            guard let mouseButton = MouseEventView(event).mouseButton,\n                  Int(mouseButton.rawValue) == mouseButtonNumber else {\n                return false\n            }\n        } else if button?.logitechControl != nil {\n            // Logitech control mappings are matched directly via handleLogitechControlEvent,\n            // not through the CGEvent pipeline.\n            return false\n        }\n\n        if let scroll {\n            guard event.type == .scrollWheel else {\n                return false\n            }\n\n            let view = ScrollWheelEventView(event)\n\n            switch scroll {\n            case .up:\n                guard view.deltaY > 0 else {\n                    return false\n                }\n            case .down:\n                guard view.deltaY < 0 else {\n                    return false\n                }\n            case .left:\n                guard view.deltaX > 0 else {\n                    return false\n                }\n            case .right:\n                guard view.deltaX < 0 else {\n                    return false\n                }\n            }\n        }\n\n        return true\n    }\n\n    func conflicted(with mapping: Self) -> Bool {\n        guard scroll == mapping.scroll,\n              conflicts(withModifierFlagsOf: mapping) else {\n            return false\n        }\n\n        return button == mapping.button\n    }\n\n    func matches(modifierFlags eventFlags: CGEventFlags) -> Bool {\n        ModifierState.generic(from: eventFlags) == modifierFlags\n    }\n\n    private func conflicts(withModifierFlagsOf mapping: Self) -> Bool {\n        modifierFlags == mapping.modifierFlags\n    }\n}\n\nextension Scheme.Buttons.Mapping: Comparable {\n    static func < (lhs: Scheme.Buttons.Mapping, rhs: Scheme.Buttons.Mapping) -> Bool {\n        func score(_ mapping: Scheme.Buttons.Mapping) -> Int {\n            var score = 0\n\n            if let mouseButtonNumber = mapping.button?.mouseButtonNumber {\n                score |= ((mouseButtonNumber & 0xFF) << 8)\n            }\n\n            if let logiButtonID = mapping.button?.logitechControl?.controlID {\n                score |= ((logiButtonID & 0xFFFF) << 20)\n                score |= ((mapping.button?.logitechControl?.specificityScore ?? 0) << 18)\n            } else if mapping.button == nil, mapping.scroll != nil {\n                score |= (1 << 16)\n            }\n\n            if mapping.modifierFlags.contains(.maskCommand) {\n                score |= (1 << 0)\n            }\n            if mapping.modifierFlags.contains(.maskShift) {\n                score |= (1 << 1)\n            }\n            if mapping.modifierFlags.contains(.maskAlternate) {\n                score |= (1 << 2)\n            }\n            if mapping.modifierFlags.contains(.maskControl) {\n                score |= (1 << 3)\n            }\n\n            return score\n        }\n\n        return score(lhs) < score(rhs)\n    }\n}\n\nextension Scheme.Buttons.Mapping: Codable {\n    private enum CodingKeys: String, CodingKey {\n        case button\n        case logiButton\n        case logitechControl\n        case `repeat`\n        case hold\n        case scroll\n        case command\n        case shift\n        case option\n        case control\n        case action\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n\n        button = try container.decodeIfPresent(Button.self, forKey: .button)\n            ?? container.decodeIfPresent(LogitechControlIdentity.self, forKey: .logiButton).map(Button.logitechControl)\n            ?? container.decodeIfPresent(LogitechControlIdentity.self, forKey: .logitechControl)\n            .map(Button.logitechControl)\n        `repeat` = try container.decodeIfPresent(Bool.self, forKey: .repeat)\n        hold = try container.decodeIfPresent(Bool.self, forKey: .hold)\n        scroll = try container.decodeIfPresent(ScrollDirection.self, forKey: .scroll)\n        command = try container.decodeIfPresent(Bool.self, forKey: .command)\n        shift = try container.decodeIfPresent(Bool.self, forKey: .shift)\n        option = try container.decodeIfPresent(Bool.self, forKey: .option)\n        control = try container.decodeIfPresent(Bool.self, forKey: .control)\n        action = try container.decodeIfPresent(Action.self, forKey: .action)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n\n        try container.encodeIfPresent(button, forKey: .button)\n        try container.encodeIfPresent(`repeat`, forKey: .repeat)\n        try container.encodeIfPresent(hold, forKey: .hold)\n        try container.encodeIfPresent(scroll, forKey: .scroll)\n        try container.encodeIfPresent(command, forKey: .command)\n        try container.encodeIfPresent(shift, forKey: .shift)\n        try container.encodeIfPresent(option, forKey: .option)\n        try container.encodeIfPresent(control, forKey: .control)\n        try container.encodeIfPresent(action, forKey: .action)\n    }\n}\n\nextension Scheme.Buttons.Mapping.Button: Codable {\n    private enum CodingKeys: String, CodingKey {\n        case kind\n    }\n\n    private enum Kind: String, Codable {\n        case logitechControl\n    }\n\n    init(from decoder: Decoder) throws {\n        if let buttonNumber = try? decoder.singleValueContainer().decode(Int.self) {\n            self = .mouse(buttonNumber)\n            return\n        }\n\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        switch try container.decode(Kind.self, forKey: .kind) {\n        case .logitechControl:\n            self = try .logitechControl(LogitechControlIdentity(from: decoder))\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        switch self {\n        case let .mouse(buttonNumber):\n            var container = encoder.singleValueContainer()\n            try container.encode(buttonNumber)\n        case let .logitechControl(identity):\n            try identity.encode(to: encoder)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/If/If.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\n\nextension Scheme {\n    struct If: Codable, Equatable {\n        var device: DeviceMatcher?\n\n        var app: String?\n        var parentApp: String?\n        var groupApp: String?\n\n        // Match by executable instead of app bundle\n        var processName: String?\n        var processPath: String?\n\n        var display: String?\n    }\n}\n\nextension Scheme.If {\n    func isSatisfied(\n        withDevice targetDevice: Device? = nil,\n        withApp targetApp: String? = nil,\n        withParentApp targetParentApp: String?,\n        withGroupApp targetGroupApp: String?,\n        withDisplay targetDisplay: String? = nil,\n        withProcessName targetProcessName: String? = nil,\n        withProcessPath targetProcessPath: String? = nil\n    ) -> Bool {\n        if let device {\n            guard let targetDevice else {\n                return false\n            }\n\n            guard device.match(with: targetDevice) else {\n                return false\n            }\n        }\n\n        if let app {\n            guard app == targetApp else {\n                return false\n            }\n        }\n\n        if let parentApp {\n            guard parentApp == targetParentApp else {\n                return false\n            }\n        }\n\n        if let groupApp {\n            guard groupApp == targetGroupApp else {\n                return false\n            }\n        }\n\n        if let processName {\n            guard processName == targetProcessName else {\n                return false\n            }\n        }\n\n        if let processPath {\n            guard processPath == targetProcessPath else {\n                return false\n            }\n        }\n\n        if let display {\n            guard let targetDisplay else {\n                return false\n            }\n\n            guard display == targetDisplay else {\n                return false\n            }\n        }\n\n        return true\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Pointer.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme {\n    struct Acceleration: Equatable, ClampRange {\n        typealias Value = Unsettable<Decimal>\n        typealias RangeValue = Decimal\n\n        static var range: ClosedRange<RangeValue> = 0 ... 20\n\n        static func clamp(_ value: Value?) -> Value? {\n            guard let value else {\n                return nil\n            }\n            switch value {\n            case let .value(v):\n                return .value(v.clamped(to: range))\n            case .unset:\n                return .unset\n            }\n        }\n    }\n\n    struct Speed: Equatable, ClampRange {\n        typealias Value = Unsettable<Decimal>\n        typealias RangeValue = Decimal\n\n        static var range: ClosedRange<RangeValue> = 0 ... 1\n\n        static func clamp(_ value: Value?) -> Value? {\n            guard let value else {\n                return nil\n            }\n            switch value {\n            case let .value(v):\n                return .value(v.clamped(to: range))\n            case .unset:\n                return .unset\n            }\n        }\n    }\n\n    struct Pointer: Codable, Equatable, ImplicitInitable {\n        @Clamp<Acceleration> var acceleration: Unsettable<Decimal>?\n\n        @Clamp<Speed> var speed: Unsettable<Decimal>?\n\n        var disableAcceleration: Bool?\n        var redirectsToScroll: Bool?\n    }\n}\n\nextension Scheme.Pointer {\n    func merge(into pointer: inout Self) {\n        if let acceleration {\n            pointer.acceleration = acceleration\n        }\n\n        if let speed {\n            pointer.speed = speed\n        }\n\n        if let disableAcceleration {\n            pointer.disableAcceleration = disableAcceleration\n        }\n\n        if let redirectsToScroll {\n            pointer.redirectsToScroll = redirectsToScroll\n        }\n    }\n\n    func merge(into pointer: inout Self?) {\n        if pointer == nil {\n            pointer = Self()\n        }\n\n        merge(into: &pointer!)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scheme.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\n/// A scheme is a set of settings to be applied to LinearMouse, for example,\n/// pointer speed.\n///\n/// A scheme will be active only if its `if` is truthy. If multiple `if`s are\n/// provided, the scheme is regarded as active if any one of them is truthy.\n///\n/// There can be multiple active schemes at the same time. Settings in\n/// subsequent schemes will be merged into the previous ones.\nstruct Scheme: Codable, Equatable {\n    /// Defines the conditions under which this scheme is active.\n    @SingleValueOrArray var `if`: [If]?\n\n    @ImplicitOptional var scrolling: Scrolling\n\n    @ImplicitOptional var pointer: Pointer\n\n    @ImplicitOptional var buttons: Buttons\n\n    init(\n        if: [If]? = nil,\n        scrolling: Scrolling? = nil,\n        pointer: Pointer? = nil,\n        buttons: Buttons? = nil\n    ) {\n        self.if = `if`\n        $scrolling = scrolling\n        $pointer = pointer\n        $buttons = buttons\n    }\n}\n\nextension Scheme {\n    func isActive(\n        withDevice device: Device? = nil,\n        withApp app: String? = nil,\n        withParentApp parentApp: String? = nil,\n        withGroupApp groupApp: String? = nil,\n        withDisplay display: String? = nil,\n        withProcessName processName: String? = nil,\n        withProcessPath processPath: String? = nil\n    ) -> Bool {\n        guard let `if` else {\n            return true\n        }\n\n        return `if`.contains {\n            $0.isSatisfied(\n                withDevice: device,\n                withApp: app,\n                withParentApp: parentApp,\n                withGroupApp: groupApp,\n                withDisplay: display,\n                withProcessName: processName,\n                withProcessPath: processPath\n            )\n        }\n    }\n\n    /// A scheme is device-specific if and only if a) it has only one `if` and\n    /// b) the `if` contains conditions that specifies both vendorID and productID.\n    var isDeviceSpecific: Bool {\n        guard let conditions = `if` else {\n            return false\n        }\n\n        guard conditions.count == 1,\n              let condition = conditions.first else {\n            return false\n        }\n\n        guard condition.device?.vendorID != nil,\n              condition.device?.productID != nil else {\n            return false\n        }\n\n        return true\n    }\n\n    var isDisplaySpecific: Bool {\n        `if`?.contains { $0.display != nil } ?? false\n    }\n\n    var matchedDevices: [Device] {\n        DeviceManager.shared.devices.filter { isActive(withDevice: $0) }\n    }\n\n    var firstMatchedDevice: Device? {\n        DeviceManager.shared.devices.first { isActive(withDevice: $0) }\n    }\n\n    func merge(into scheme: inout Self) {\n        $scrolling?.merge(into: &scheme.scrolling)\n        $pointer?.merge(into: &scheme.pointer)\n        $buttons?.merge(into: &scheme.buttons)\n    }\n}\n\nextension Scheme: CustomStringConvertible {\n    var description: String {\n        do {\n            return try String(data: JSONEncoder().encode(self), encoding: .utf8) ?? \"<Scheme>\"\n        } catch {\n            return \"<Scheme>\"\n        }\n    }\n}\n\nextension [Scheme] {\n    func allDeviceSpecficSchemes(of device: Device) -> [EnumeratedSequence<[Scheme]>.Element] {\n        self.enumerated().filter { _, scheme in\n            guard scheme.isDeviceSpecific else {\n                return false\n            }\n            guard scheme.if?.count == 1, let `if` = scheme.if?.first else {\n                return false\n            }\n            guard `if`.device?.match(with: device) == true else {\n                return false\n            }\n            return true\n        }\n    }\n\n    enum SchemeIndex {\n        case at(Int)\n        case insertAt(Int)\n    }\n\n    func schemeIndex(\n        ofDevice device: Device,\n        ofApp app: String?,\n        ofProcessPath processPath: String?,\n        ofDisplay display: String?\n    ) -> SchemeIndex {\n        let allDeviceSpecificSchemes = allDeviceSpecficSchemes(of: device)\n\n        guard let first = allDeviceSpecificSchemes.first,\n              let last = allDeviceSpecificSchemes.last else {\n            return .insertAt(self.endIndex)\n        }\n\n        if let (index, _) = allDeviceSpecificSchemes\n            .first(where: { _, scheme in\n                scheme.if?.first?.app == app &&\n                    scheme.if?.first?.processPath == processPath &&\n                    scheme.if?.first?.display == display\n            }) {\n            return .at(index)\n        }\n\n        if app == nil, processPath == nil, display == nil {\n            return .insertAt(first.offset)\n        }\n\n        if app != nil || processPath != nil, display != nil {\n            return .insertAt(last.offset + 1)\n        }\n\n        if app != nil {\n            if let (index, _) = allDeviceSpecificSchemes\n                .first(where: { _, scheme in scheme.if?.first?.app == app }) {\n                return .insertAt(index)\n            }\n        }\n\n        if processPath != nil {\n            if let (index, _) = allDeviceSpecificSchemes\n                .first(where: { _, scheme in scheme.if?.first?.processPath == processPath }) {\n                return .insertAt(index)\n            }\n        }\n\n        if display != nil {\n            if let (index, _) = allDeviceSpecificSchemes\n                .first(where: { _, scheme in scheme.if?.first?.display == display }) {\n                return .insertAt(index)\n            }\n        }\n\n        return .insertAt(last.offset + 1)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Bidirectional.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Scheme.Scrolling {\n    struct Bidirectional<T: Codable & Equatable>: Equatable, ImplicitInitable {\n        var vertical: T?\n        var horizontal: T?\n\n        func merge(into: inout Self) {\n            if let vertical {\n                into.vertical = vertical\n            }\n\n            if let horizontal {\n                into.horizontal = horizontal\n            }\n        }\n\n        func merge(into: inout Self?) {\n            if into == nil {\n                into = Self()\n            }\n\n            merge(into: &into!)\n        }\n    }\n}\n\nextension Scheme.Scrolling {\n    enum BidirectionalDirection: String, Identifiable, CaseIterable {\n        var id: Self {\n            self\n        }\n\n        case vertical = \"Vertical\"\n        case horizontal = \"Horizontal\"\n    }\n}\n\nextension Scheme.Scrolling.Bidirectional {\n    subscript(direction: Scheme.Scrolling.BidirectionalDirection) -> T? {\n        get {\n            switch direction {\n            case .vertical:\n                return vertical\n            case .horizontal:\n                return horizontal\n            }\n        }\n        set {\n            switch direction {\n            case .vertical:\n                vertical = newValue\n            case .horizontal:\n                horizontal = newValue\n            }\n        }\n    }\n}\n\nextension Scheme.Scrolling.Bidirectional: Codable {\n    enum CodingKeys: CodingKey {\n        case vertical, horizontal\n    }\n\n    init(from decoder: Decoder) throws {\n        do {\n            let container = try decoder.container(keyedBy: CodingKeys.self)\n            guard container.contains(.vertical) || container.contains(.horizontal) else {\n                throw DecodingError.typeMismatch(\n                    Self.self,\n                    .init(\n                        codingPath: container.codingPath,\n                        debugDescription: \"Neither vertical or horizontal key found\"\n                    )\n                )\n            }\n            vertical = try container.decodeIfPresent(T.self, forKey: .vertical)\n            horizontal = try container.decodeIfPresent(T.self, forKey: .horizontal)\n        } catch DecodingError.valueNotFound(_, _), DecodingError.typeMismatch(_, _) {\n            let container = try decoder.singleValueContainer()\n            if container.decodeNil() {\n                return\n            }\n            let v = try container.decode(T?.self)\n            vertical = v\n            horizontal = v\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        if vertical == horizontal {\n            var container = encoder.singleValueContainer()\n            try container.encode(vertical)\n            return\n        }\n\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        if let vertical {\n            try container.encode(vertical, forKey: .vertical)\n        }\n        if let horizontal {\n            try container.encode(horizontal, forKey: .horizontal)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Distance+Mode.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Scheme.Scrolling.Distance {\n    enum Mode: CaseIterable, Identifiable {\n        var id: Self {\n            self\n        }\n\n        case byLines\n        case byPixels\n    }\n\n    var mode: Mode {\n        switch self {\n        case .auto, .line:\n            return .byLines\n        case .pixel:\n            return .byPixels\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Distance.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme.Scrolling {\n    enum Distance: Equatable, Hashable {\n        case auto\n        case line(Int)\n        case pixel(Decimal)\n    }\n}\n\nextension Scheme.Scrolling.Distance: CustomStringConvertible {\n    var description: String {\n        switch self {\n        case .auto:\n            return NSLocalizedString(\"auto\", comment: \"\")\n        case let .line(value):\n            return String(format: NSLocalizedString(\"%d line(s)\", comment: \"\"), value)\n        case let .pixel(value):\n            return String(format: NSLocalizedString(\"%.1f pixel(s)\", comment: \"\"), value.asTruncatedDouble)\n        }\n    }\n}\n\nextension Scheme.Scrolling.Distance: Codable {\n    enum ValueError: Error {\n        case invalidValue\n        case unknownUnit\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n        do {\n            let value = try container.decode(Int.self)\n            self = .line(value)\n        } catch {\n            let stringValue = try container.decode(String.self)\n\n            if stringValue == \"auto\" {\n                self = .auto\n                return\n            }\n\n            let regex = try NSRegularExpression(pattern: #\"^([\\d.]+)(px|)$\"#, options: [])\n\n            let matches = regex.matches(\n                in: stringValue,\n                range: NSRange(stringValue.startIndex ..< stringValue.endIndex, in: stringValue)\n            )\n            guard let match = matches.first else {\n                throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n            }\n\n            guard let valueRange = Range(match.range(at: 1), in: stringValue) else {\n                throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n            }\n\n            guard let unitRange = Range(match.range(at: 2), in: stringValue) else {\n                throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n            }\n\n            let valueString = String(stringValue[valueRange])\n            let unitString = String(stringValue[unitRange])\n\n            switch unitString {\n            case \"\":\n                guard let value = Int(valueString, radix: 10) else {\n                    throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n                }\n\n                self = .line(value)\n\n            case \"px\":\n                guard let value = Decimal(string: valueString) else {\n                    throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n                }\n\n                self = .pixel(value)\n\n            default:\n                throw CustomDecodingError(in: container, error: ValueError.unknownUnit)\n            }\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n\n        switch self {\n        case .auto:\n            try container.encode(\"auto\")\n        case let .line(value):\n            try container.encode(value)\n        case let .pixel(value):\n            try container.encode(\"\\(value)px\")\n        }\n    }\n}\n\nextension Scheme.Scrolling.Distance.ValueError: LocalizedError {\n    var errorDescription: String? {\n        switch self {\n        case .invalidValue:\n            return NSLocalizedString(\n                \"Distance must be \\\"auto\\\" or a number or a string representing value and unit\",\n                comment: \"\"\n            )\n        case .unknownUnit:\n            return NSLocalizedString(\"Unit must be empty or \\\"px\\\"\", comment: \"\")\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Modifiers+Kind.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Scheme.Scrolling.Modifiers.Action {\n    enum Kind: CaseIterable, Identifiable {\n        var id: Self {\n            self\n        }\n\n        case defaultAction\n        case ignore\n        case noAction\n        case alterOrientation\n        case changeSpeed\n        case zoom\n        case pinchZoom\n    }\n\n    var kind: Kind {\n        switch self {\n        case .auto:\n            return .defaultAction\n        case .ignore:\n            return .ignore\n        case .preventDefault:\n            return .noAction\n        case .alterOrientation:\n            return .alterOrientation\n        case .changeSpeed:\n            return .changeSpeed\n        case .zoom:\n            return .zoom\n        case .pinchZoom:\n            return .pinchZoom\n        }\n    }\n\n    init(kind: Kind) {\n        switch kind {\n        case .defaultAction:\n            self = .auto\n        case .ignore:\n            self = .ignore\n        case .noAction:\n            self = .preventDefault\n        case .alterOrientation:\n            self = .alterOrientation\n        case .changeSpeed:\n            self = .changeSpeed(scale: 1)\n        case .zoom:\n            self = .zoom\n        case .pinchZoom:\n            self = .pinchZoom\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Modifiers.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme.Scrolling {\n    struct Modifiers: Equatable, Codable, ImplicitInitable {\n        var command: Action?\n        var shift: Action?\n        var option: Action?\n        var control: Action?\n    }\n}\n\nextension Scheme.Scrolling.Modifiers {\n    enum Action: Equatable {\n        case auto\n        case ignore\n        case preventDefault\n        case alterOrientation\n        case changeSpeed(scale: Decimal)\n        case zoom\n        case pinchZoom\n    }\n}\n\nextension Scheme.Scrolling.Modifiers {\n    func merge(into modifiers: inout Self) {\n        if let command {\n            modifiers.command = command\n        }\n\n        if let shift {\n            modifiers.shift = shift\n        }\n\n        if let option {\n            modifiers.option = option\n        }\n\n        if let control {\n            modifiers.control = control\n        }\n    }\n\n    func merge(into modifiers: inout Self?) {\n        if modifiers == nil {\n            modifiers = Self()\n        }\n\n        merge(into: &modifiers!)\n    }\n}\n\nextension Scheme.Scrolling.Modifiers.Action: Codable {\n    enum CodingKeys: String, CodingKey {\n        case type, scale\n    }\n\n    enum ActionType: String, Codable {\n        @available(*, deprecated)\n        case none\n        case auto\n        case ignore\n        case preventDefault\n        case alterOrientation\n        case changeSpeed\n        case zoom\n        case pinchZoom\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        let type = try container.decode(ActionType.self, forKey: .type)\n\n        switch type {\n        case .none, .auto:\n            self = .auto\n        case .ignore:\n            self = .ignore\n        case .preventDefault:\n            self = .preventDefault\n        case .alterOrientation:\n            self = .alterOrientation\n        case .changeSpeed:\n            let scale = try container.decode(Decimal.self, forKey: .scale)\n            self = .changeSpeed(scale: scale)\n        case .zoom:\n            self = .zoom\n        case .pinchZoom:\n            self = .pinchZoom\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n\n        switch self {\n        case .auto:\n            try container.encode(ActionType.auto, forKey: .type)\n        case .ignore:\n            try container.encode(ActionType.ignore, forKey: .type)\n        case .preventDefault:\n            try container.encode(ActionType.preventDefault, forKey: .type)\n        case .alterOrientation:\n            try container.encode(ActionType.alterOrientation, forKey: .type)\n        case let .changeSpeed(scale):\n            try container.encode(ActionType.changeSpeed, forKey: .type)\n            try container.encode(scale, forKey: .scale)\n        case .zoom:\n            try container.encode(ActionType.zoom, forKey: .type)\n        case .pinchZoom:\n            try container.encode(ActionType.pinchZoom, forKey: .type)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Scrolling.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Scheme {\n    struct Scrolling: Codable, Equatable, ImplicitInitable {\n        @ImplicitOptional var reverse: Bidirectional<Bool>\n        @ImplicitOptional var distance: Bidirectional<Distance>\n        @ImplicitOptional var acceleration: Bidirectional<Decimal>\n        @ImplicitOptional var speed: Bidirectional<Decimal>\n        @ImplicitOptional var smoothed: Bidirectional<Smoothed>\n        @ImplicitOptional var modifiers: Bidirectional<Modifiers>\n\n        init() {}\n\n        init(\n            reverse: Bidirectional<Bool>? = nil,\n            distance: Bidirectional<Distance>? = nil,\n            acceleration: Bidirectional<Decimal>? = nil,\n            speed: Bidirectional<Decimal>? = nil,\n            smoothed: Bidirectional<Smoothed>? = nil,\n            modifiers: Bidirectional<Modifiers>? = nil\n        ) {\n            $reverse = reverse\n            $distance = distance\n            $acceleration = acceleration\n            $speed = speed\n            $smoothed = smoothed\n            $modifiers = modifiers\n        }\n    }\n}\n\nextension Scheme.Scrolling {\n    func merge(into scrolling: inout Self) {\n        $reverse?.merge(into: &scrolling.reverse)\n        $distance?.merge(into: &scrolling.distance)\n        $acceleration?.merge(into: &scrolling.acceleration)\n        $speed?.merge(into: &scrolling.speed)\n        merge(smoothed: $smoothed, into: &scrolling.smoothed)\n        $modifiers?.merge(into: &scrolling.modifiers)\n    }\n\n    func merge(into scrolling: inout Self?) {\n        if scrolling == nil {\n            scrolling = Self()\n        }\n\n        merge(into: &scrolling!)\n    }\n\n    private func merge(smoothed source: Bidirectional<Smoothed>?, into target: inout Bidirectional<Smoothed>) {\n        guard let source else {\n            return\n        }\n\n        var merged = target\n\n        if let sourceVertical = source.vertical {\n            if merged.vertical == nil {\n                merged.vertical = sourceVertical\n            } else {\n                sourceVertical.merge(into: &merged.vertical!)\n            }\n        }\n\n        if let sourceHorizontal = source.horizontal {\n            if merged.horizontal == nil {\n                merged.horizontal = sourceHorizontal\n            } else {\n                sourceHorizontal.merge(into: &merged.horizontal!)\n            }\n        }\n\n        target = merged\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/Configuration/Scheme/Scrolling/Smoothed.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport SwiftUI\n\nextension Scheme.Scrolling {\n    struct Smoothed: Equatable, Codable, ImplicitInitable {\n        struct PresetProfile: Equatable {\n            var response: Double\n            var inputExponent: Double\n            var accelerationGain: Double\n            var decay: Double\n            var velocityScale: Double\n        }\n\n        enum Preset: String, Codable, Equatable, CaseIterable, Identifiable {\n            var id: Self {\n                self\n            }\n\n            case custom\n            case linear\n            case easeIn\n            case easeOut\n            case easeInOut\n            case quadratic\n            case cubic\n            case quartic\n            case easeOutCubic\n            case easeInOutCubic\n            case easeOutQuartic\n            case easeInOutQuartic\n            case smooth\n        }\n\n        var enabled: Bool?\n        var preset: Preset?\n        var response: Decimal?\n        var speed: Decimal?\n        var acceleration: Decimal?\n        var inertia: Decimal?\n\n        init() {}\n\n        init(\n            enabled: Bool? = nil,\n            preset: Preset? = nil,\n            response: Decimal? = nil,\n            speed: Decimal? = nil,\n            acceleration: Decimal? = nil,\n            inertia: Decimal? = nil\n        ) {\n            self.enabled = enabled\n            self.preset = preset\n            self.response = response\n            self.speed = speed\n            self.acceleration = acceleration\n            self.inertia = inertia\n        }\n    }\n}\n\nextension Scheme.Scrolling.Smoothed {\n    static let responseRange: ClosedRange<Double> = 0.0 ... 2.0\n    static let speedRange: ClosedRange<Double> = 0.0 ... 8.0\n    static let accelerationRange: ClosedRange<Double> = 0.0 ... 8.0\n    static let inertiaRange: ClosedRange<Double> = 0.0 ... 8.0\n\n    var resolvedPreset: Preset {\n        preset ?? .defaultPreset\n    }\n\n    var resolvedPresetProfile: PresetProfile {\n        resolvedPreset.profile\n    }\n\n    var isEnabled: Bool {\n        enabled ?? true\n    }\n\n    func merge(into smoothed: inout Self) {\n        if let enabled {\n            smoothed.enabled = enabled\n        }\n\n        if let preset {\n            smoothed.preset = preset\n        }\n\n        if let response {\n            smoothed.response = response\n        }\n\n        if let speed {\n            smoothed.speed = speed\n        }\n\n        if let acceleration {\n            smoothed.acceleration = acceleration\n        }\n\n        if let inertia {\n            smoothed.inertia = inertia\n        }\n    }\n\n    func merge(into smoothed: inout Self?) {\n        if smoothed == nil {\n            smoothed = Self()\n        }\n\n        merge(into: &smoothed!)\n    }\n}\n\nextension Scheme.Scrolling.Smoothed.Preset {\n    struct Presentation: Equatable {\n        var title: LocalizedStringKey\n        var subtitle: LocalizedStringKey\n        var showsEditableBadge = false\n    }\n\n    static var defaultPreset: Self {\n        .easeInOut\n    }\n\n    static var recommendedCases: [Self] {\n        [\n            .easeInOut,\n            .easeIn,\n            .easeOut,\n            .linear,\n            .quadratic,\n            .cubic,\n            .easeOutCubic,\n            .easeInOutCubic,\n            .quartic,\n            .easeOutQuartic,\n            .easeInOutQuartic,\n            .smooth,\n            .custom\n        ]\n    }\n\n    var profile: Scheme.Scrolling.Smoothed.PresetProfile {\n        switch self {\n        case .custom:\n            return .init(response: 0.64, inputExponent: 1.00, accelerationGain: 0.10, decay: 0.89, velocityScale: 32)\n        case .linear:\n            return .init(response: 0.94, inputExponent: 0.96, accelerationGain: 0.04, decay: 0.83, velocityScale: 34)\n        case .easeIn:\n            return .init(response: 0.34, inputExponent: 1.18, accelerationGain: 0.08, decay: 0.93, velocityScale: 24)\n        case .easeOut:\n            return .init(response: 0.90, inputExponent: 0.92, accelerationGain: 0.08, decay: 0.84, velocityScale: 34)\n        case .easeInOut:\n            return .init(response: 0.68, inputExponent: 1.06, accelerationGain: 0.10, decay: 0.89, velocityScale: 31)\n        case .quadratic:\n            return .init(response: 0.58, inputExponent: 1.12, accelerationGain: 0.12, decay: 0.88, velocityScale: 33)\n        case .cubic:\n            return .init(response: 0.52, inputExponent: 1.18, accelerationGain: 0.14, decay: 0.89, velocityScale: 35)\n        case .quartic:\n            return .init(response: 0.46, inputExponent: 1.24, accelerationGain: 0.16, decay: 0.90, velocityScale: 37)\n        case .easeOutCubic:\n            return .init(response: 0.94, inputExponent: 0.86, accelerationGain: 0.08, decay: 0.82, velocityScale: 35)\n        case .easeInOutCubic:\n            return .init(response: 0.62, inputExponent: 1.12, accelerationGain: 0.12, decay: 0.89, velocityScale: 33)\n        case .easeOutQuartic:\n            return .init(response: 0.98, inputExponent: 0.80, accelerationGain: 0.08, decay: 0.80, velocityScale: 36)\n        case .easeInOutQuartic:\n            return .init(response: 0.56, inputExponent: 1.18, accelerationGain: 0.14, decay: 0.90, velocityScale: 34)\n        case .smooth:\n            return .init(response: 0.80, inputExponent: 0.98, accelerationGain: 0.06, decay: 0.93, velocityScale: 33)\n        }\n    }\n\n    var presentation: Presentation {\n        switch self {\n        case .custom:\n            return .init(\n                title: \"Custom\",\n                subtitle: \"Use this when you want to fine-tune the feel yourself.\",\n                showsEditableBadge: true\n            )\n        case .linear:\n            return .init(title: \"Linear\", subtitle: \"Direct and immediate, with a short controlled tail.\")\n        case .easeIn:\n            return .init(title: \"Ease In\", subtitle: \"Soft start that builds momentum as you keep scrolling.\")\n        case .easeOut:\n            return .init(title: \"Ease Out\", subtitle: \"Fast initial response that settles quickly.\")\n        case .easeInOut:\n            return .init(title: \"Ease In Out\", subtitle: \"Balanced ramp-up and release.\")\n        case .quadratic:\n            return .init(title: \"Ease In Quad\", subtitle: \"Ease-in quad with a noticeable but manageable ramp-up.\")\n        case .cubic:\n            return .init(title: \"Ease In Cubic\", subtitle: \"Ease-in cubic with a stronger progressive build.\")\n        case .quartic:\n            return .init(title: \"Ease In Quartic\", subtitle: \"Ease-in quartic with the strongest front-loaded ramp.\")\n        case .easeOutCubic:\n            return .init(title: \"Ease Out Cubic\", subtitle: \"Fast cubic pickup that settles into a shorter tail.\")\n        case .easeInOutCubic:\n            return .init(title: \"Ease In Out Cubic\", subtitle: \"Cubic ease-in-out with a weightier middle section.\")\n        case .easeOutQuartic:\n            return .init(title: \"Ease Out Quartic\", subtitle: \"Very fast quartic pickup with a crisp release.\")\n        case .easeInOutQuartic:\n            return .init(title: \"Ease In Out Quartic\", subtitle: \"Quartic ease-in-out with the boldest mid-curve.\")\n        case .smooth:\n            return .init(title: \"Smooth\", subtitle: \"Stable and fluid, with a longer carry than Linear.\")\n        }\n    }\n\n    var defaultConfiguration: Scheme.Scrolling.Smoothed {\n        let values: (response: Decimal, speed: Decimal, acceleration: Decimal, inertia: Decimal)\n\n        switch self {\n        case .custom:\n            values = (0.68, 1.00, 1.00, 0.80)\n        case .linear:\n            values = (0.92, 1.00, 0.78, 0.44)\n        case .easeIn:\n            values = (0.38, 0.92, 0.86, 1.00)\n        case .easeOut:\n            values = (0.88, 1.02, 0.94, 0.42)\n        case .easeInOut:\n            values = (0.68, 1.02, 1.10, 0.74)\n        case .quadratic:\n            values = (0.58, 1.04, 1.18, 0.72)\n        case .cubic:\n            values = (0.54, 1.08, 1.24, 0.76)\n        case .quartic:\n            values = (0.48, 1.12, 1.32, 0.82)\n        case .easeOutCubic:\n            values = (0.94, 1.06, 0.92, 0.42)\n        case .easeInOutCubic:\n            values = (0.62, 1.06, 1.20, 0.78)\n        case .easeOutQuartic:\n            values = (0.98, 1.10, 0.90, 0.38)\n        case .easeInOutQuartic:\n            values = (0.56, 1.10, 1.28, 0.82)\n        case .smooth:\n            values = (0.80, 1.00, 0.88, 0.92)\n        }\n\n        return .init(\n            enabled: true,\n            preset: self,\n            response: values.response,\n            speed: values.speed,\n            acceleration: values.acceleration,\n            inertia: values.inertia\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Model/DeviceModel.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\nimport SwiftUI\n\nclass DeviceModel: ObservableObject, Identifiable {\n    let id: Int32\n\n    let deviceRef: WeakRef<Device>\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    @Published var isActive = false\n\n    @Published var name: String\n    @Published var displayName: String\n    @Published var batteryLevel: Int?\n    @Published var pairedReceiverDevices: [ReceiverLogicalDeviceIdentity] = []\n    let category: Device.Category\n    private let baseName: String\n\n    init(deviceRef: WeakRef<Device>) {\n        self.deviceRef = deviceRef\n        id = deviceRef.value?.id ?? 0\n\n        let initialName = deviceRef.value?.name ?? \"(removed)\"\n        baseName = initialName\n        name = initialName\n        displayName = initialName\n        batteryLevel = deviceRef.value?.batteryLevel\n        category = deviceRef.value?.category ?? .mouse\n\n        DeviceManager.shared\n            .$lastActiveDeviceRef\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .removeDuplicates()\n            .map { deviceRef.value != nil && $0?.value == deviceRef.value }\n            .sink { [weak self] value in\n                self?.isActive = value\n            }\n            .store(in: &subscriptions)\n\n        DeviceManager.shared\n            .$receiverPairedDeviceIdentities\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.refreshReceiverPresentation()\n            }\n            .store(in: &subscriptions)\n\n        BatteryDeviceMonitor.shared\n            .$devices\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.refreshBatteryLevel()\n            }\n            .store(in: &subscriptions)\n\n        refreshReceiverPresentation()\n        refreshBatteryLevel()\n\n        DevicePickerBatteryCoordinator.shared.refresh(self)\n    }\n\n    func applyVendorSpecificMetadata(_ metadata: VendorSpecificDeviceMetadata?) {\n        if let name = metadata?.name {\n            self.name = name\n        }\n\n        batteryLevel = metadata?.batteryLevel\n        refreshReceiverPresentation()\n        refreshBatteryLevel()\n    }\n\n    private func refreshReceiverPresentation() {\n        guard let device = deviceRef.value else {\n            name = \"(removed)\"\n            displayName = \"(removed)\"\n            pairedReceiverDevices = []\n            return\n        }\n\n        let preferredName = DeviceManager.shared.preferredName(for: device, fallback: name)\n        let pairedDevices = DeviceManager.shared.pairedReceiverDevices(for: device)\n\n        name = preferredName\n        pairedReceiverDevices = pairedDevices\n        displayName = DeviceManager.displayName(baseName: preferredName, pairedDevices: pairedDevices)\n    }\n\n    private func refreshBatteryLevel() {\n        guard let device = deviceRef.value else {\n            batteryLevel = nil\n            return\n        }\n\n        batteryLevel = BatteryDeviceMonitor.shared.currentDeviceBatteryLevel(for: device) ?? device.batteryLevel\n    }\n\n    func resetVendorSpecificMetadata() {\n        name = baseName\n        refreshReceiverPresentation()\n        refreshBatteryLevel()\n    }\n}\n\nextension DeviceModel {\n    var batteryDescription: String? {\n        guard pairedReceiverDevices.isEmpty else {\n            return nil\n        }\n\n        return batteryLevel.map(formattedPercent)\n    }\n\n    var isMouse: Bool {\n        category == .mouse\n    }\n\n    var isTrackpad: Bool {\n        category == .trackpad\n    }\n}\n"
  },
  {
    "path": "LinearMouse/ModifierKeys.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nstruct ModifierKeyAction: Codable {\n    var type: ModifierKeyActionType\n    var speedFactor: Double\n}\n\nenum ModifierKeyActionType: String, Codable, CaseIterable {\n    case noAction = \"No action\"\n    case alterOrientation = \"Alter orientation\"\n    case changeSpeed = \"Change speed\"\n}\n\nextension ModifierKeyAction {\n    var schemeAction: Scheme.Scrolling.Modifiers.Action {\n        switch type {\n        case .noAction:\n            return .preventDefault\n        case .alterOrientation:\n            return .alterOrientation\n        case .changeSpeed:\n            return .changeSpeed(scale: Decimal(speedFactor))\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/ScreenManager/ScreenManager.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Combine\nimport CoreGraphics\nimport os.log\n\nclass ScreenManager: ObservableObject {\n    static let shared = ScreenManager()\n\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"ScreenManager\")\n\n    @Published private(set) var screens: [NSScreen] = []\n\n    @Published private(set) var currentScreen: NSScreen?\n    @Published private(set) var currentScreenName: String? {\n        didSet {\n            screenNameLock.withLock { _currentScreenNameSnapshot = currentScreenName }\n        }\n    }\n\n    /// Thread-safe access to `currentScreenName`, for use from the background event tap thread.\n    private let screenNameLock = NSLock()\n    private var _currentScreenNameSnapshot: String?\n    var currentScreenNameSnapshot: String? {\n        screenNameLock.withLock { _currentScreenNameSnapshot }\n    }\n\n    private var hasDisplaySpecificSchemes = false\n    private var timer: Timer?\n\n    private var subscriptions: Set<AnyCancellable> = []\n\n    init() {\n        NotificationCenter.default\n            .publisher(for: NSApplication.didChangeScreenParametersNotification)\n            .sink { [weak self] _ in\n                guard let self else {\n                    return\n                }\n\n                self.updateScreens()\n                self.update()\n            }\n            .store(in: &subscriptions)\n\n        ConfigurationState.shared\n            .$configuration\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .sink { [weak self] configuration in\n                guard let self else {\n                    return\n                }\n\n                self.hasDisplaySpecificSchemes = configuration.schemes.contains(where: \\.isDisplaySpecific)\n                self.update()\n            }\n            .store(in: &subscriptions)\n\n        DispatchQueue.main.async { [weak self] in\n            guard let self else {\n                return\n            }\n\n            self.updateScreens()\n            self.update()\n        }\n    }\n\n    private func updateScreens() {\n        screens = NSScreen.screens\n        os_log(\"Displays changed: %{public}@\", String(describing: screens))\n    }\n\n    private func update() {\n        let screen = screens.first { $0.frame.contains(NSEvent.mouseLocation) }\n        if currentScreen != screen {\n            currentScreen = screen\n            currentScreenName = screen?.nameOrLocalizedName\n            os_log(\n                \"Current display changed: %{public}@: %{public}@\",\n                String(describing: screen),\n                String(describing: currentScreenName)\n            )\n        }\n\n        if let timer {\n            timer.invalidate()\n            self.timer = nil\n        }\n\n        guard screens.count > 1 else {\n            os_log(\"Display switching disabled due to single display\")\n            return\n        }\n\n        guard hasDisplaySpecificSchemes else {\n            os_log(\"Display switching disabled due to no display-specific schemes\")\n            return\n        }\n\n        timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { [weak self] _ in\n            guard let self else {\n                return\n            }\n\n            DispatchQueue.main.async {\n                self.update()\n            }\n        }\n    }\n}\n\nextension NSScreen {\n    var displayID: CGDirectDisplayID? {\n        deviceDescription[NSDeviceDescriptionKey(\"NSScreenNumber\")] as? CGDirectDisplayID\n    }\n\n    var ioServicePort: io_service_t? {\n        guard let displayID else {\n            return nil\n        }\n\n        var iter = io_iterator_t()\n        guard IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(\"IODisplayConnect\"), &iter) ==\n            KERN_SUCCESS else {\n            return nil\n        }\n\n        defer { IOObjectRelease(iter) }\n\n        var service = IOIteratorNext(iter)\n        while true {\n            guard service != MACH_PORT_NULL else {\n                break\n            }\n\n            let info = IODisplayCreateInfoDictionary(service, IOOptionBits(kIODisplayOnlyPreferredName))\n                .takeRetainedValue() as NSDictionary\n\n            let vendorID = info.value(forKey: kDisplayVendorID) as? UInt32\n            let productID = info.value(forKey: kDisplayProductID) as? UInt32\n            let serialNumber = info.value(forKey: kDisplaySerialNumber) as? UInt32\n\n            if CGDisplayVendorNumber(displayID) == vendorID,\n               CGDisplayModelNumber(displayID) == productID,\n               CGDisplaySerialNumber(displayID) == serialNumber ?? 0 {\n                return service\n            }\n\n            IOObjectRelease(service)\n            service = IOIteratorNext(iter)\n        }\n\n        return nil\n    }\n\n    var name: String? {\n        guard let service = ioServicePort else {\n            return nil\n        }\n\n        defer { IOObjectRelease(service) }\n\n        let info = IODisplayCreateInfoDictionary(service, IOOptionBits(kIODisplayOnlyPreferredName))\n            .takeRetainedValue() as NSDictionary\n\n        let productNames = info.value(forKey: kDisplayProductName) as? NSDictionary\n\n        return productNames?.allValues.first as? String\n    }\n\n    var nameOrLocalizedName: String {\n        name ?? localizedName\n    }\n}\n"
  },
  {
    "path": "LinearMouse/State/ConfigurationState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Combine\nimport Darwin\nimport Defaults\nimport Foundation\nimport os.log\nimport SwiftUI\n\nclass ConfigurationState: ObservableObject {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"AppDelegate\")\n\n    static let shared = ConfigurationState()\n\n    var configurationPaths: [URL] {\n        var urls: [URL] = []\n\n        if let applicationSupportURL = FileManager.default\n            .urls(for: .applicationSupportDirectory, in: .userDomainMask)\n            .first {\n            urls.append(\n                URL(\n                    fileURLWithPath: \"linearmouse/linearmouse.json\",\n                    relativeTo: applicationSupportURL\n                )\n            )\n        }\n\n        urls.append(\n            URL(\n                fileURLWithPath: \".config/linearmouse/linearmouse.json\",\n                relativeTo: FileManager.default.homeDirectoryForCurrentUser\n            )\n        )\n\n        return urls\n    }\n\n    var configurationPath: URL {\n        configurationPaths.first { FileManager.default.fileExists(atPath: $0.absoluteString) } ?? configurationPaths\n            .last!\n    }\n\n    private var configurationSaveDebounceTimer: Timer?\n    @Published var configuration = Configuration() {\n        didSet {\n            configurationSaveDebounceTimer?.invalidate()\n            guard !loading else {\n                return\n            }\n\n            configurationSaveDebounceTimer = Timer.scheduledTimer(\n                withTimeInterval: 0.2,\n                repeats: false\n            ) { [weak self] _ in\n                guard let self else {\n                    return\n                }\n\n                os_log(\n                    \"Saving new configuration: %{public}@\",\n                    log: Self.log,\n                    type: .info,\n                    String(describing: self.configuration)\n                )\n                self.save()\n            }\n        }\n    }\n\n    @Published private(set) var loading = false\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    // Hot reload support (watch parent directory and resolved target file)\n    private var configDirFD: CInt?\n    private var configDirSource: DispatchSourceFileSystemObject?\n    private var configFileFD: CInt?\n    private var configFileSource: DispatchSourceFileSystemObject?\n    private var watchedFilePath: String?\n    private var reloadDebounceWorkItem: DispatchWorkItem?\n}\n\nextension ConfigurationState {\n    func reloadFromDisk() {\n        do {\n            let newConfig = try Configuration.load(from: configurationPath)\n            guard newConfig != configuration else {\n                return\n            }\n\n            loading = true\n            configuration = newConfig\n            loading = false\n\n            Notifier.shared.notify(\n                title: NSLocalizedString(\"Configuration Reloaded\", comment: \"\"),\n                body: NSLocalizedString(\"Your configuration changes are now active.\", comment: \"\")\n            )\n        } catch CocoaError.fileReadNoSuchFile {\n            loading = true\n            configuration = .init()\n            loading = false\n\n            Notifier.shared.notify(\n                title: NSLocalizedString(\"Configuration Reloaded\", comment: \"\"),\n                body: NSLocalizedString(\"Your configuration changes are now active.\", comment: \"\")\n            )\n        } catch {\n            Notifier.shared.notify(\n                title: NSLocalizedString(\"Failed to reload configuration\", comment: \"\"),\n                body: error.localizedDescription\n            )\n        }\n    }\n\n    func startHotReload() {\n        stopHotReload()\n\n        // Directory watcher\n        let directoryURL = configurationPath.deletingLastPathComponent()\n        let dirFD = open(directoryURL.path, O_EVTONLY)\n        guard dirFD >= 0 else {\n            return\n        }\n        configDirFD = dirFD\n\n        let dirSource = DispatchSource.makeFileSystemObjectSource(\n            fileDescriptor: dirFD,\n            eventMask: [.write, .attrib, .rename, .link, .delete, .extend, .revoke],\n            queue: .main\n        )\n\n        dirSource.setEventHandler { [weak self] in\n            guard let self else {\n                return\n            }\n            // Any directory entry change may indicate symlink retarget, file replace, create/delete, etc.\n            self.updateFileWatcherIfNeeded()\n            self.scheduleReloadFromExternalChange()\n        }\n\n        dirSource.setCancelHandler { [weak self] in\n            if let fd = self?.configDirFD {\n                close(fd)\n            }\n            self?.configDirFD = nil\n        }\n\n        configDirSource = dirSource\n        dirSource.resume()\n\n        // File watcher for resolved target (or the file itself if not a symlink)\n        updateFileWatcherIfNeeded()\n    }\n\n    func stopHotReload() {\n        reloadDebounceWorkItem?.cancel()\n        reloadDebounceWorkItem = nil\n\n        configDirSource?.cancel()\n        configDirSource = nil\n        if let fd = configDirFD {\n            close(fd)\n        }\n        configDirFD = nil\n\n        configFileSource?.cancel()\n        configFileSource = nil\n        if let fd = configFileFD {\n            close(fd)\n        }\n        configFileFD = nil\n        watchedFilePath = nil\n    }\n\n    private func scheduleReloadFromExternalChange() {\n        reloadDebounceWorkItem?.cancel()\n        let work = DispatchWorkItem { [weak self] in\n            self?.reloadFromDisk()\n        }\n        reloadDebounceWorkItem = work\n        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25, execute: work)\n    }\n\n    private func updateFileWatcherIfNeeded() {\n        // Watch resolved target file (or the file itself if not a symlink)\n        let linkPath = configurationPath.path\n        let resolvedPath = (linkPath as NSString).resolvingSymlinksInPath\n\n        // If path unchanged, nothing to do\n        if watchedFilePath == resolvedPath, configFileSource != nil {\n            // Still ensure file exists; if gone, drop watcher so directory watcher can recreate later\n            if !FileManager.default.fileExists(atPath: resolvedPath) {\n                configFileSource?.cancel()\n                configFileSource = nil\n                if let fd = configFileFD {\n                    close(fd)\n                }\n                configFileFD = nil\n                watchedFilePath = nil\n            }\n            return\n        }\n\n        // Path changed or no watcher; rebuild\n        configFileSource?.cancel()\n        configFileSource = nil\n        if let fd = configFileFD {\n            close(fd)\n        }\n        configFileFD = nil\n        watchedFilePath = nil\n\n        guard FileManager.default.fileExists(atPath: resolvedPath) else {\n            return\n        }\n\n        let fd = open(resolvedPath, O_EVTONLY)\n        guard fd >= 0 else {\n            return\n        }\n        configFileFD = fd\n\n        let fileSource = DispatchSource.makeFileSystemObjectSource(\n            fileDescriptor: fd,\n            eventMask: [.write, .attrib, .extend, .delete, .rename, .revoke, .link],\n            queue: .main\n        )\n\n        fileSource.setEventHandler { [weak self] in\n            guard let self else {\n                return\n            }\n            let events = fileSource.data\n            if events.contains(.delete) || events.contains(.rename) || events.contains(.revoke) {\n                // File removed/replaced; drop watcher and rely on directory watcher to re-add\n                self.configFileSource?.cancel()\n                self.configFileSource = nil\n                if let fd = self.configFileFD {\n                    close(fd)\n                }\n                self.configFileFD = nil\n                self.watchedFilePath = nil\n                self.scheduleReloadFromExternalChange()\n            } else {\n                self.scheduleReloadFromExternalChange()\n            }\n        }\n\n        fileSource.setCancelHandler { [weak self] in\n            if let fd = self?.configFileFD {\n                close(fd)\n            }\n            self?.configFileFD = nil\n        }\n\n        configFileSource = fileSource\n        watchedFilePath = resolvedPath\n        fileSource.resume()\n    }\n\n    func revealInFinder() {\n        NSWorkspace.shared.activateFileViewerSelecting([ConfigurationState.shared.configurationPath.absoluteURL])\n    }\n\n    func load() {\n        loading = true\n        defer {\n            loading = false\n        }\n\n        do {\n            configuration = try Configuration.load(from: configurationPath)\n        } catch CocoaError.fileReadNoSuchFile {\n            os_log(\n                \"No configuration file found, try creating a default one\",\n                log: Self.log,\n                type: .info\n            )\n            save()\n        } catch {\n            let alert = NSAlert()\n            alert.messageText = String(\n                format: NSLocalizedString(\"Failed to load the configuration: %@\", comment: \"\"),\n                error.localizedDescription\n            )\n            alert.runModal()\n        }\n    }\n\n    func save() {\n        do {\n            try configuration.dump(to: configurationPath)\n        } catch {\n            let alert = NSAlert()\n            alert.messageText = String(\n                format: NSLocalizedString(\"Failed to save the configuration: %@\", comment: \"\"),\n                error.localizedDescription\n            )\n            alert.runModal()\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/State/DeviceState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Defaults\nimport SwiftUI\n\nextension Defaults.Keys {\n    static let autoSwitchToActiveDevice = Key<Bool>(\"autoSwitchToActiveDevice\", default: true)\n\n    static let selectedDevice = Key<DeviceMatcher?>(\"selectedDevice\", default: nil)\n}\n\nclass DeviceState: ObservableObject {\n    static let shared = DeviceState()\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    @Published var currentDeviceRef: WeakRef<Device>? {\n        didSet {\n            guard !Defaults[.autoSwitchToActiveDevice] else {\n                return\n            }\n\n            let currentDeviceMatcher = currentDeviceRef?.value.map { DeviceMatcher(of: $0) }\n            guard Defaults[.selectedDevice] != currentDeviceMatcher else {\n                return\n            }\n\n            Defaults[.selectedDevice] = currentDeviceMatcher\n        }\n    }\n\n    init() {\n        Defaults.observe(keys: .autoSwitchToActiveDevice, .selectedDevice) { [weak self] in\n            self?.updateCurrentDevice()\n        }\n        .tieToLifetime(of: self)\n\n        Defaults.observe(.autoSwitchToActiveDevice) { change in\n            if change.newValue {\n                Defaults[.selectedDevice] = nil\n            }\n        }\n        .tieToLifetime(of: self)\n\n        deviceManager.$lastActiveDeviceRef\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .removeDuplicates()\n            .sink { [weak self] lastActiveDeviceRef in\n                self?.updateCurrentDeviceRef(lastActiveDeviceRef: lastActiveDeviceRef)\n            }\n            .store(in: &subscriptions)\n\n        deviceManager.$devices\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.updateCurrentDevice()\n            }\n            .store(in: &subscriptions)\n    }\n}\n\nextension DeviceState {\n    private var deviceManager: DeviceManager {\n        DeviceManager.shared\n    }\n\n    private func updateCurrentDeviceRef(lastActiveDeviceRef: WeakRef<Device>?) {\n        guard !Defaults[.autoSwitchToActiveDevice] else {\n            currentDeviceRef = lastActiveDeviceRef\n            return\n        }\n\n        guard let userSelectedDevice = Defaults[.selectedDevice] else {\n            currentDeviceRef = lastActiveDeviceRef\n            return\n        }\n\n        let matchedDeviceRef = deviceManager.devices\n            .first { userSelectedDevice.match(with: $0) }\n            .map { WeakRef($0) }\n\n        currentDeviceRef = matchedDeviceRef ?? lastActiveDeviceRef\n    }\n\n    private func updateCurrentDevice() {\n        updateCurrentDeviceRef(lastActiveDeviceRef: deviceManager.lastActiveDeviceRef)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/State/ModifierState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\n\nfinal class ModifierState {\n    static let shared = ModifierState()\n\n    static let genericFlags: CGEventFlags = [\n        .maskCommand,\n        .maskShift,\n        .maskAlternate,\n        .maskControl\n    ]\n\n    static let sideSpecificFlags = CGEventFlags(rawValue: UInt64(\n        NX_DEVICELCTLKEYMASK |\n            NX_DEVICERCTLKEYMASK |\n            NX_DEVICELSHIFTKEYMASK |\n            NX_DEVICERSHIFTKEYMASK |\n            NX_DEVICELALTKEYMASK |\n            NX_DEVICERALTKEYMASK |\n            NX_DEVICELCMDKEYMASK |\n            NX_DEVICERCMDKEYMASK\n    ))\n\n    static let relevantFlags = genericFlags.union(sideSpecificFlags)\n\n    private let lock = NSLock()\n    private var currentFlagsStorage: CGEventFlags\n\n    private init() {\n        currentFlagsStorage = Self.normalize(CGEventSource.flagsState(.combinedSessionState))\n    }\n\n    var currentFlags: CGEventFlags {\n        lock.lock()\n        defer { lock.unlock() }\n        return currentFlagsStorage\n    }\n\n    func update(with event: CGEvent) {\n        guard [.flagsChanged, .keyDown, .keyUp].contains(event.type),\n              !event.isLinearMouseSyntheticEvent else {\n            return\n        }\n\n        lock.lock()\n        currentFlagsStorage = Self.normalize(event.flags)\n        lock.unlock()\n    }\n\n    static func normalize(_ flags: CGEventFlags) -> CGEventFlags {\n        flags.intersection(relevantFlags)\n    }\n\n    static func generic(from flags: CGEventFlags) -> CGEventFlags {\n        normalize(flags).intersection(genericFlags)\n    }\n\n    static func sideSpecific(from flags: CGEventFlags) -> CGEventFlags {\n        normalize(flags).intersection(sideSpecificFlags)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/State/SchemeState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\n\nclass SchemeState: ObservableObject {\n    static let shared = SchemeState()\n\n    private let configurationState: ConfigurationState = .shared\n    private let deviceState: DeviceState = .shared\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    @Published var currentApp: AppTarget?\n    @Published var currentDisplay: String?\n\n    init() {\n        configurationState.$configuration\n            .sink { [weak self] _ in\n                self?.objectWillChange.send()\n            }\n            .store(in: &subscriptions)\n\n        deviceState.$currentDeviceRef\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .removeDuplicates()\n            .sink { [weak self] _ in\n                self?.objectWillChange.send()\n            }\n            .store(in: &subscriptions)\n    }\n}\n\nextension SchemeState {\n    private var device: Device? {\n        deviceState.currentDeviceRef?.value\n    }\n\n    private func hasMatchingSchemes(for device: Device?, app: AppTarget?, display: String?) -> Bool {\n        guard let device else {\n            return false\n        }\n\n        let (appId, processPath) = extractAppComponents(from: app)\n\n        return schemes.contains { scheme in\n            guard let conditions = scheme.if else {\n                return false\n            }\n\n            return conditions.contains { condition in\n                guard let deviceMatcher = condition.device,\n                      deviceMatcher.match(with: device) else {\n                    return false\n                }\n\n                let appMatches = condition.app == appId && condition.processPath == processPath\n                let displayMatches = condition.display == display\n\n                return appMatches && displayMatches\n            }\n        }\n    }\n\n    private func deleteMatchingSchemes(for device: Device?, app: AppTarget?, display: String?) {\n        guard let device else {\n            return\n        }\n\n        let (appId, processPath) = extractAppComponents(from: app)\n\n        schemes.removeAll { scheme in\n            guard let conditions = scheme.if else {\n                return false\n            }\n\n            return conditions.contains { condition in\n                guard let deviceMatcher = condition.device,\n                      deviceMatcher.match(with: device) else {\n                    return false\n                }\n\n                let appMatches = condition.app == appId && condition.processPath == processPath\n                let displayMatches = condition.display == display\n\n                return appMatches && displayMatches\n            }\n        }\n    }\n\n    var isSchemeValid: Bool {\n        guard device != nil else {\n            return false\n        }\n\n        return true\n    }\n\n    var schemes: [Scheme] {\n        get { configurationState.configuration.schemes }\n        set { configurationState.configuration.schemes = newValue }\n    }\n\n    var currentAppName: String? {\n        switch currentApp {\n        case .none:\n            return nil\n        case let .bundle(bundleIdentifier):\n            return try? readInstalledApp(bundleIdentifier: bundleIdentifier)?.bundleName ?? bundleIdentifier\n        case let .executable(path):\n            return URL(fileURLWithPath: path).lastPathComponent\n        }\n    }\n\n    var scheme: Scheme {\n        get {\n            guard let device else {\n                return Scheme()\n            }\n\n            let (app, processPath) = extractAppComponents(from: currentApp)\n\n            if case let .at(index) = schemes.schemeIndex(\n                ofDevice: device,\n                ofApp: app,\n                ofProcessPath: processPath,\n                ofDisplay: currentDisplay\n            ) {\n                return schemes[index]\n            }\n\n            var ifCondition = Scheme.If(device: .init(of: device))\n            ifCondition.app = app\n            ifCondition.processPath = processPath\n            ifCondition.display = currentDisplay\n\n            return Scheme(if: [ifCondition])\n        }\n\n        set {\n            guard let device else {\n                return\n            }\n\n            let (app, processPath) = extractAppComponents(from: currentApp)\n\n            switch schemes.schemeIndex(\n                ofDevice: device,\n                ofApp: app,\n                ofProcessPath: processPath,\n                ofDisplay: currentDisplay\n            ) {\n            case let .at(index):\n                schemes[index] = newValue\n            case let .insertAt(index):\n                schemes.insert(newValue, at: index)\n            }\n        }\n    }\n\n    private func extractAppComponents(from target: AppTarget?) -> (app: String?, processPath: String?) {\n        switch target {\n        case .none:\n            return (nil, nil)\n        case let .bundle(bundleIdentifier):\n            return (bundleIdentifier, nil)\n        case let .executable(path):\n            return (nil, path)\n        }\n    }\n\n    var mergedScheme: Scheme {\n        guard let device else {\n            return Scheme()\n        }\n\n        let (app, processPath) = extractAppComponents(from: currentApp)\n\n        return configurationState.configuration.matchScheme(\n            withDevice: device,\n            withApp: app,\n            withDisplay: currentDisplay,\n            withProcessPath: processPath\n        )\n    }\n\n    var hasMatchingSchemes: Bool {\n        hasMatchingSchemes(forApp: currentApp, forDisplay: currentDisplay)\n    }\n\n    func hasMatchingSchemes(for device: Device?, forApp app: AppTarget?, forDisplay display: String?) -> Bool {\n        hasMatchingSchemes(for: device, app: app, display: display)\n    }\n\n    func hasMatchingSchemes(forApp app: AppTarget?, forDisplay display: String?) -> Bool {\n        hasMatchingSchemes(for: device, app: app, display: display)\n    }\n\n    func deleteMatchingSchemes() {\n        deleteMatchingSchemes(forApp: currentApp, forDisplay: currentDisplay)\n    }\n\n    func deleteMatchingSchemes(for device: Device?, forApp app: AppTarget?, forDisplay display: String?) {\n        deleteMatchingSchemes(for: device, app: app, display: display)\n    }\n\n    func deleteMatchingSchemes(forApp app: AppTarget?, forDisplay display: String?) {\n        deleteMatchingSchemes(for: device, app: app, display: display)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/State/SettingsState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport Foundation\nimport SwiftUI\n\nclass SettingsState: ObservableObject {\n    static let shared = SettingsState()\n\n    struct RecordedVirtualButtonEvent {\n        let button: Scheme.Buttons.Mapping.Button\n        let modifierFlags: CGEventFlags\n    }\n\n    struct VirtualButtonRecordingPreparation: Equatable {\n        let sessionID: UUID\n        var pendingDeviceIDs: Set<Int32>\n    }\n\n    enum Navigation: String, CaseIterable, Hashable {\n        case pointer, scrolling, buttons, general\n\n        var title: LocalizedStringKey {\n            switch self {\n            case .pointer:\n                return \"Pointer\"\n            case .scrolling:\n                return \"Scrolling\"\n            case .buttons:\n                return \"Buttons\"\n            case .general:\n                return \"General\"\n            }\n        }\n\n        var imageName: String {\n            switch self {\n            case .pointer:\n                return \"Pointer\"\n            case .scrolling:\n                return \"Scrolling\"\n            case .buttons:\n                return \"Buttons\"\n            case .general:\n                return \"General\"\n            }\n        }\n    }\n\n    @Published var navigation: Navigation? = .pointer\n\n    /// When `recording` is true, `ButtonActionsTransformer` should be temporarily disabled.\n    @Published var recording = false\n\n    /// A short-lived preparation phase used while Logitech monitors temporarily divert all controls\n    /// for recording. Standard CGEvents can still be recorded immediately.\n    @Published private(set) var virtualButtonRecordingPreparation: VirtualButtonRecordingPreparation?\n\n    /// Set by protocol-backed button monitors when a virtual button is pressed during recording.\n    /// The recorder uses the event-time modifier snapshot to avoid races with later key-up events.\n    @Published var recordedVirtualButtonEvent: RecordedVirtualButtonEvent?\n\n    var isPreparingVirtualButtonRecording: Bool {\n        virtualButtonRecordingPreparation != nil\n    }\n\n    var virtualButtonRecordingSessionID: UUID? {\n        virtualButtonRecordingPreparation?.sessionID\n    }\n\n    func beginVirtualButtonRecordingPreparation(for deviceIDs: Set<Int32>) {\n        guard !deviceIDs.isEmpty else {\n            virtualButtonRecordingPreparation = nil\n            return\n        }\n\n        virtualButtonRecordingPreparation = .init(\n            sessionID: UUID(),\n            pendingDeviceIDs: deviceIDs\n        )\n    }\n\n    func finishVirtualButtonRecordingPreparation(for deviceID: Int32, sessionID: UUID) {\n        guard var preparation = virtualButtonRecordingPreparation,\n              preparation.sessionID == sessionID else {\n            return\n        }\n\n        preparation.pendingDeviceIDs.remove(deviceID)\n        virtualButtonRecordingPreparation = preparation.pendingDeviceIDs.isEmpty ? nil : preparation\n    }\n\n    func endVirtualButtonRecordingPreparation() {\n        virtualButtonRecordingPreparation = nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/AccessibilityPermissionView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport os.log\nimport SwiftUI\n\nstruct AccessibilityPermissionView: View {\n    private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: \"AccessibilityPermissionView\")\n\n    var body: some View {\n        VStack(alignment: .leading, spacing: 10) {\n            HStack(spacing: 15) {\n                Image(\"AccessibilityIcon\")\n\n                Text(\"LinearMouse needs Accessibility permission\")\n                    .font(.headline)\n            }\n            .padding(.horizontal)\n\n            Text(\n                \"You need to grant Accessibility permission in System Settings > Security & Privacy > Accessibility.\"\n            )\n            .padding(.horizontal)\n\n            HyperLink(URL(string: \"https://go.linearmouse.app/accessibility-permission\")!) {\n                Text(\"Get more help\")\n            }\n            .padding(.horizontal)\n\n            Spacer()\n\n            HStack {\n                Button(\"Open Accessibility\") {\n                    openAccessibility()\n                }\n            }\n        }\n        .padding()\n        .frame(width: 450, height: 200)\n    }\n\n    func openAccessibility() {\n        AccessibilityPermission.prompt()\n        AccessibilityPermissionWindow.shared.moveAside()\n    }\n}\n\nstruct AccessibilityPermissionView_Previews: PreviewProvider {\n    static var previews: some View {\n        AccessibilityPermissionView()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/AccessibilityPermissionWindow.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport SwiftUI\n\nclass AccessibilityPermissionWindow: NSWindow {\n    static let shared = AccessibilityPermissionWindow()\n\n    init() {\n        super.init(\n            contentRect: .init(x: 0, y: 0, width: 450, height: 200),\n            styleMask: [.titled, .closable, .fullSizeContentView],\n            backing: .buffered,\n            defer: false\n        )\n\n        delegate = self\n\n        isReleasedWhenClosed = true\n\n        contentView = NSHostingView(rootView: AccessibilityPermissionView())\n\n        titleVisibility = .hidden\n        titlebarAppearsTransparent = true\n\n        level = .floating\n\n        center()\n\n        AccessibilityPermission.pollingUntilEnabled {\n            self.close()\n        }\n    }\n\n    func moveAside() {\n        if let screenFrame = screen?.visibleFrame {\n            let origin = CGPoint(x: screenFrame.maxX - frame.width, y: frame.minY)\n            setFrame(.init(origin: origin, size: frame.size), display: true, animate: true)\n        }\n    }\n}\n\nextension AccessibilityPermissionWindow: NSWindowDelegate {\n    func windowWillClose(_: Notification) {\n        guard AccessibilityPermission.enabled else {\n            NSApplication.shared.terminate(nil)\n            exit(0)\n        }\n\n        Application.restart()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"18122\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"18122\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"LinearMouse\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"LinearMouse\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About LinearMouse\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide LinearMouse\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit LinearMouse\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontFontPanel:\" target=\"YLy-65-1bz\" id=\"WHr-nq-2xA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"hqk-hr-sYV\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\">\n                                                        <connections>\n                                                            <action selector=\"addFontTrait:\" target=\"YLy-65-1bz\" id=\"IHV-OB-c03\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"Uc7-di-UnL\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\">\n                                                        <connections>\n                                                            <action selector=\"modifyFont:\" target=\"YLy-65-1bz\" id=\"HcX-Lf-eNd\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSidebar:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"LinearMouse Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModule=\"LinearMouse\" customModuleProvider=\"target\"/>\n                <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "LinearMouse/UI/ButtonStyle/SecondaryButtonStyle.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct SecondaryButtonStyle: ButtonStyle {\n    func makeBody(configuration: ButtonStyle.Configuration) -> some View {\n        if #available(macOS 26.0, *) {\n            configuration.label\n                .padding(.vertical, 3)\n                .padding(.horizontal, 6)\n                .glassEffect(.regular.interactive())\n        } else {\n            configuration.label\n                .padding(.vertical, 3)\n                .padding(.horizontal, 6)\n                .background(Color.gray.opacity(configuration.isPressed ? 0.3 : 0.1))\n                .cornerRadius(3)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/AutoScrollSection/AutoScrollSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct AutoScrollSection: View {\n    @ObservedObject private var state: ButtonsSettingsState = .shared\n\n    var body: some View {\n        Section {\n            Toggle(isOn: $state.autoScrollEnabled.animation()) {\n                withDescription {\n                    Text(\"Enable autoscroll\")\n                    Text(\n                        \"Scroll by moving away from an anchor point, similar to Windows middle-click autoscroll.\"\n                    )\n                }\n            }\n\n            if state.autoScrollEnabled {\n                VStack(alignment: .leading, spacing: 8) {\n                    Text(\"Modes\")\n                        .font(.headline)\n\n                    Toggle(\"Click once to toggle\", isOn: $state.autoScrollToggleModeEnabled.animation())\n                        .disabled(state.autoScrollToggleModeEnabled && !state.autoScrollHoldModeEnabled)\n\n                    Toggle(\"Hold to scroll\", isOn: $state.autoScrollHoldModeEnabled.animation())\n                        .disabled(state.autoScrollHoldModeEnabled && !state.autoScrollToggleModeEnabled)\n                }\n\n                VStack(alignment: .leading, spacing: 8) {\n                    Text(\"Trigger\")\n                        .font(.headline)\n\n                    ButtonMappingButtonRecorder(\n                        mapping: state.autoScrollTriggerBinding\n                    )\n\n                    if !state.autoScrollTriggerValid {\n                        Text(\"Choose a mouse button trigger. Left click without modifier keys is not allowed.\")\n                            .foregroundColor(.red)\n                            .controlSize(.small)\n                            .fixedSize(horizontal: false, vertical: true)\n                    }\n                }\n\n                VStack(alignment: .leading, spacing: 4) {\n                    HStack {\n                        Text(\"Speed\")\n                        Spacer()\n                        Text(state.autoScrollSpeedText)\n                            .foregroundColor(.secondary)\n                    }\n\n                    Slider(value: $state.autoScrollSpeed, in: 0.3 ... 3.0, step: 0.1)\n                }\n\n                Toggle(isOn: $state.autoScrollPreserveNativeMiddleClick.animation()) {\n                    withDescription {\n                        Text(\"Preserve native middle-click on links and buttons\")\n                        Text(\n                            \"When using plain middle click, keep browser-style middle-click behavior on pressable elements instead of entering autoscroll.\"\n                        )\n                    }\n                }\n                .disabled(!state.autoScrollPreserveNativeMiddleClickAvailable)\n\n                if !state.autoScrollUsesPlainMiddleClick {\n                    Text(\n                        \"The native middle-click check only applies when the trigger is middle click without modifier keys.\"\n                    )\n                    .foregroundColor(.secondary)\n                    .controlSize(.small)\n                    .fixedSize(horizontal: false, vertical: true)\n                } else if !state.autoScrollToggleModeEnabled {\n                    Text(\"The native middle-click check only applies when click once to toggle is enabled.\")\n                        .foregroundColor(.secondary)\n                        .controlSize(.small)\n                        .fixedSize(horizontal: false, vertical: true)\n                }\n\n                Text(modeDescription)\n                    .font(.caption)\n                    .foregroundColor(.secondary)\n                    .padding(.top, 4)\n            }\n        }\n        .modifier(SectionViewModifier())\n    }\n\n    private var modeDescription: LocalizedStringKey {\n        let modes = Set(state.autoScrollModes)\n\n        if modes == [.toggle] {\n            return \"Click the trigger once to enter autoscroll, move in any direction to scroll, then click again to exit.\"\n        }\n\n        if modes == [.hold] {\n            return \"Hold the trigger while moving to scroll, then release it to stop.\"\n        }\n\n        return \"Click and release to keep autoscroll active, or hold and drag to scroll only until you let go.\"\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMapping.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingListItem: View {\n    @Binding var mapping: Scheme.Buttons.Mapping\n\n    @State private var hover = false\n\n    @State private var showEditSheet = false\n    @State private var mappingToEdit: Scheme.Buttons.Mapping = .init()\n\n    var body: some View {\n        HStack {\n            VStack(alignment: .leading, spacing: 2) {\n                ButtonMappingButtonDescription<EmptyView>(mapping: mapping)\n                ButtonMappingActionDescription(action: mapping.action ?? .arg0(.auto))\n            }\n\n            Spacer()\n\n            Button(\"Edit\") {\n                mappingToEdit = mapping\n                showEditSheet.toggle()\n            }\n            .opacity(hover ? 1 : 0)\n        }\n        .padding(.vertical, 4)\n        .sheet(isPresented: $showEditSheet) {\n            ButtonMappingEditSheet(isPresented: $showEditSheet, mapping: $mappingToEdit) { mapping in\n                self.mapping = mapping\n            }\n        }\n        .onHover {\n            hover = $0\n        }\n    }\n}\n\nstruct ButtonMappingButtonDescription<FallbackView: View>: View {\n    var mapping: Scheme.Buttons.Mapping\n    var showPartial = false\n    var fallback: (() -> FallbackView)?\n\n    var body: some View {\n        if let button = mapping.button {\n            descriptionRow {\n                Text(buttonDescription(of: button))\n            }\n        } else if let scroll = mapping.scroll {\n            descriptionRow {\n                Text(scrollDescription(of: scroll))\n            }\n        } else if showPartial, !mapping.modifierFlags.isEmpty {\n            Text(modifiersDescription)\n        } else {\n            if let fallback {\n                fallback()\n            } else {\n                Text(\"Not specified\")\n            }\n        }\n    }\n\n    private var modifiersDescription: String {\n        let flags = mapping.modifierFlags\n        let modifierDescriptions: [(Bool, String)] = [\n            (flags.contains(CGEventFlags.maskControl), \"⌃\"),\n            (flags.contains(CGEventFlags.maskAlternate), \"⌥\"),\n            (flags.contains(CGEventFlags.maskShift), \"⇧\"),\n            (flags.contains(CGEventFlags.maskCommand), \"⌘\")\n        ]\n\n        return modifierDescriptions\n            .compactMap { $0.0 == true ? $0.1 : nil }\n            .joined()\n    }\n\n    @ViewBuilder\n    private func descriptionRow<Content: View>(@ViewBuilder content: () -> Content) -> some View {\n        if modifiersDescription.isEmpty {\n            content()\n        } else {\n            HStack(spacing: 5) {\n                Text(modifiersDescription)\n                content()\n            }\n        }\n    }\n\n    private func buttonDescription(of button: Scheme.Buttons.Mapping.Button) -> LocalizedStringKey {\n        switch button {\n        case let .mouse(buttonNumber):\n            switch buttonNumber {\n            case 0:\n                return \"Primary click\"\n            case 1:\n                return \"Secondary click\"\n            case 2:\n                return \"Middle click\"\n            default:\n                return \"Button #\\(buttonNumber) click\"\n            }\n        case let .logitechControl(identity):\n            return LocalizedStringKey(identity.userVisibleName)\n        }\n    }\n\n    private func scrollDescription(of scroll: Scheme.Buttons.Mapping.ScrollDirection) -> LocalizedStringKey {\n        switch scroll {\n        case .up:\n            return \"Scroll up\"\n        case .down:\n            return \"Scroll down\"\n        case .left:\n            return \"Scroll left\"\n        case .right:\n            return \"Scroll right\"\n        }\n    }\n}\n\nstruct ButtonMappingActionDescription: View {\n    var action: Scheme.Buttons.Mapping.Action\n\n    var body: some View {\n        Text(action.description)\n            .foregroundColor(.secondary)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ButtonMappingAction+Binding.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport KeyKit\nimport SwiftUI\n\nextension Binding where Value == Scheme.Buttons.Mapping.Action {\n    var kind: Binding<Scheme.Buttons.Mapping.Action.Kind> {\n        Binding<Scheme.Buttons.Mapping.Action.Kind>(\n            get: {\n                wrappedValue.kind\n            },\n            set: {\n                wrappedValue = Scheme.Buttons.Mapping.Action(kind: $0)\n            }\n        )\n    }\n\n    var runCommand: Binding<String> {\n        Binding<String>(\n            get: {\n                guard case let .arg1(.run(command)) = wrappedValue else {\n                    return \"\"\n                }\n\n                return command\n            },\n            set: {\n                wrappedValue = .arg1(.run($0))\n            }\n        )\n    }\n\n    var scrollDistance: Binding<Scheme.Scrolling.Distance> {\n        Binding<Scheme.Scrolling.Distance>(\n            get: {\n                switch wrappedValue {\n                case let .arg1(.mouseWheelScrollUp(distance)):\n                    return distance\n                case let .arg1(.mouseWheelScrollDown(distance)):\n                    return distance\n                case let .arg1(.mouseWheelScrollLeft(distance)):\n                    return distance\n                case let .arg1(.mouseWheelScrollRight(distance)):\n                    return distance\n                default:\n                    return .line(3)\n                }\n            },\n            set: {\n                switch wrappedValue {\n                case .arg1(.mouseWheelScrollUp):\n                    wrappedValue = .arg1(.mouseWheelScrollUp($0))\n                case .arg1(.mouseWheelScrollDown):\n                    wrappedValue = .arg1(.mouseWheelScrollDown($0))\n                case .arg1(.mouseWheelScrollLeft):\n                    wrappedValue = .arg1(.mouseWheelScrollLeft($0))\n                case .arg1(.mouseWheelScrollRight):\n                    wrappedValue = .arg1(.mouseWheelScrollRight($0))\n                default:\n                    return\n                }\n            }\n        )\n    }\n\n    var keyPressKeys: Binding<[Key]> {\n        Binding<[Key]>(\n            get: {\n                guard case let .arg1(.keyPress(keys)) = wrappedValue else {\n                    return []\n                }\n\n                return keys\n            },\n            set: {\n                wrappedValue = .arg1(.keyPress($0))\n            }\n        )\n    }\n}\n\nextension Scheme.Buttons.Mapping.Action.Kind {\n    @ViewBuilder\n    var label: some View {\n        switch self {\n        case let .arg0(value):\n            Text(value.description.capitalized)\n        case .run:\n            Text(\"Run shell command…\")\n        case .mouseWheelScrollUp:\n            Text(\"Scroll up…\")\n        case .mouseWheelScrollDown:\n            Text(\"Scroll down…\")\n        case .mouseWheelScrollLeft:\n            Text(\"Scroll left…\")\n        case .mouseWheelScrollRight:\n            Text(\"Scroll right…\")\n        case .keyPress:\n            Text(\"Keyboard shortcut…\")\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ButtonMappingAction.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingAction: View {\n    @Binding var action: Scheme.Buttons.Mapping.Action\n\n    var body: some View {\n        ButtonMappingActionPicker(actionType: $action.kind)\n            .equatable()\n\n        switch action {\n        case .arg0:\n            EmptyView()\n        case .arg1(.run):\n            ButtonMappingActionRun(action: $action)\n        case .arg1(.mouseWheelScrollUp),\n             .arg1(.mouseWheelScrollDown),\n             .arg1(.mouseWheelScrollLeft),\n             .arg1(.mouseWheelScrollRight):\n            ButtonMappingActionScroll(action: $action)\n        case .arg1(.keyPress):\n            ButtonMappingActionKeyPress(action: $action)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ButtonMappingActionKeyPress.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport KeyKit\nimport ObservationToken\nimport SwiftUI\n\nstruct ButtonMappingActionKeyPress: View {\n    @Binding var action: Scheme.Buttons.Mapping.Action\n\n    var body: some View {\n        KeyboardShortcutRecorder(keys: $action.keyPressKeys)\n    }\n}\n\nstruct KeyboardShortcutRecorder: View {\n    @Binding var keys: [Key]\n\n    @State private var recording = false {\n        didSet {\n            guard oldValue != recording else {\n                return\n            }\n            recordingUpdated()\n        }\n    }\n\n    @State private var recordingObservationToken: ObservationToken?\n\n    @State private var recordingModifiers: CGEventFlags = []\n\n    var body: some View {\n        Button {\n            recording.toggle()\n        } label: {\n            Group {\n                if recording {\n                    Text(\"Recording\")\n                        .foregroundColor(.orange)\n                } else {\n                    if keys.isEmpty {\n                        Text(\"Click to record\")\n                    } else {\n                        Text(keys.map(\\.description).joined())\n                    }\n                }\n            }\n            .frame(maxWidth: .infinity)\n        }\n    }\n\n    private func recordingUpdated() {\n        recordingObservationToken = nil\n\n        if recording {\n            recordingModifiers = []\n\n            recordingObservationToken = try? EventTap.observe([\n                .flagsChanged,\n                .keyDown\n            ]) { _, event in\n                eventReceived(event)\n            }\n\n            if recordingObservationToken == nil {\n                recording = false\n            }\n        }\n    }\n\n    private func buildKeysFromModifierFlags(_ modifierFlags: CGEventFlags) -> [Key] {\n        var keys: [Key] = []\n\n        if modifierFlags.contains(.maskControl) {\n            keys\n                .append(modifierFlags\n                    .contains(.init(rawValue: UInt64(NX_DEVICERCTLKEYMASK))) ? .controlRight : .control\n                )\n        }\n\n        if modifierFlags.contains(.maskShift) {\n            keys.append(modifierFlags.contains(.init(rawValue: UInt64(NX_DEVICERSHIFTKEYMASK))) ? .shiftRight : .shift)\n        }\n\n        if modifierFlags.contains(.maskAlternate) {\n            keys.append(modifierFlags.contains(.init(rawValue: UInt64(NX_DEVICERALTKEYMASK))) ? .optionRight : .option)\n        }\n\n        if modifierFlags.contains(.maskCommand) {\n            keys\n                .append(modifierFlags\n                    .contains(.init(rawValue: UInt64(NX_DEVICERCMDKEYMASK))) ? .commandRight : .command\n                )\n        }\n\n        return keys\n    }\n\n    private func eventReceived(_ event: CGEvent) -> CGEvent? {\n        switch event.type {\n        case .flagsChanged:\n            recordingModifiers.insert(event.flags)\n\n            // If all modifier keys are released without and other key pressed,\n            // just record the modifier keys.\n            if event.flags.isDisjoint(with: [.maskControl, .maskShift, .maskAlternate, .maskCommand]) {\n                keys = buildKeysFromModifierFlags(recordingModifiers)\n                recording = false\n            }\n\n        case .keyDown:\n            let keyCodeResolver = KeyCodeResolver()\n            guard let key = keyCodeResolver.key(from: CGKeyCode(event.getIntegerValueField(.keyboardEventKeycode)))\n            else {\n                break\n            }\n            keys = buildKeysFromModifierFlags(event.flags) + [key]\n            recording = false\n\n        default:\n            break\n        }\n\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ButtonMappingActionPicker.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingActionPicker: View, Equatable {\n    @Binding var actionType: ActionType\n\n    var body: some View {\n        Picker(\"Action\", selection: $actionType) {\n            ActionTypeTreeView(nodes: Self.actionTypeTree)\n        }\n        .modifier(PickerViewModifier())\n    }\n\n    // swiftformat:disable:next redundantEquatable\n    static func == (lhs: Self, rhs: Self) -> Bool {\n        lhs.actionType == rhs.actionType\n    }\n}\n\nextension ButtonMappingActionPicker {\n    typealias ActionType = Scheme.Buttons.Mapping.Action.Kind\n\n    indirect enum ActionTypeTreeNode: Identifiable {\n        var id: UUID {\n            UUID()\n        }\n\n        case actionType(ActionType)\n        case section(LocalizedStringKey, () -> [Self])\n    }\n\n    struct ActionTypeTreeView: View {\n        let nodes: [ActionTypeTreeNode]\n\n        var body: some View {\n            ForEach(nodes) { node in\n                switch node {\n                case let .actionType(actionType):\n                    actionType.label.tag(actionType)\n                case let .section(header, getNodes):\n                    Section(header: Text(header)) {\n                        Self(nodes: getNodes())\n                    }\n                }\n            }\n        }\n    }\n\n    static let actionTypeTree: [ActionTypeTreeNode] = [\n        .actionType(.arg0(.auto)),\n        .actionType(.arg0(.none)),\n        .section(\"Mission Control\") { [\n            .actionType(.arg0(.missionControl)),\n            .actionType(.arg0(.missionControlSpaceLeft)),\n            .actionType(.arg0(.missionControlSpaceRight))\n        ]\n        },\n        .actionType(.arg0(.appExpose)),\n        .actionType(.arg0(.launchpad)),\n        .actionType(.arg0(.showDesktop)),\n        .actionType(.arg0(.lookUpAndDataDetectors)),\n        .actionType(.arg0(.smartZoom)),\n        .section(\"Display\") { [\n            .actionType(.arg0(.displayBrightnessUp)),\n            .actionType(.arg0(.displayBrightnessDown))\n        ]\n        },\n        .section(\"Media\") { [\n            .actionType(.arg0(.mediaVolumeUp)),\n            .actionType(.arg0(.mediaVolumeDown)),\n            .actionType(.arg0(.mediaMute)),\n            .actionType(.arg0(.mediaPlayPause)),\n            .actionType(.arg0(.mediaPrevious)),\n            .actionType(.arg0(.mediaNext)),\n            .actionType(.arg0(.mediaFastForward)),\n            .actionType(.arg0(.mediaRewind))\n        ]\n        },\n        .section(\"Keyboard\") { [\n            .actionType(.arg0(.keyboardBrightnessUp)),\n            .actionType(.arg0(.keyboardBrightnessDown)),\n            .actionType(.keyPress)\n        ]\n        },\n        .section(\"Mouse Wheel\") { [\n            .actionType(.arg0(.mouseWheelScrollUp)),\n            .actionType(.mouseWheelScrollUp),\n            .actionType(.arg0(.mouseWheelScrollDown)),\n            .actionType(.mouseWheelScrollDown),\n            .actionType(.arg0(.mouseWheelScrollLeft)),\n            .actionType(.mouseWheelScrollLeft),\n            .actionType(.arg0(.mouseWheelScrollRight)),\n            .actionType(.mouseWheelScrollRight)\n        ]\n        },\n        .section(\"Mouse Button\") { [\n            .actionType(.arg0(.mouseButtonLeft)),\n            .actionType(.arg0(.mouseButtonLeftDouble)),\n            .actionType(.arg0(.mouseButtonMiddle)),\n            .actionType(.arg0(.mouseButtonRight)),\n            .actionType(.arg0(.mouseButtonBack)),\n            .actionType(.arg0(.mouseButtonForward))\n        ]\n        },\n        .section(\"Execute\") { [\n            .actionType(.run)\n        ]\n        }\n    ]\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ButtonMappingActionRun.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingActionRun: View {\n    @Binding var action: Scheme.Buttons.Mapping.Action\n\n    var body: some View {\n        TextField(String(\"\"), text: $action.runCommand)\n            .labelsHidden()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ButtonMappingActionScroll.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingActionScroll: View {\n    @Binding var action: Scheme.Buttons.Mapping.Action\n\n    var body: some View {\n        DistanceInput(distance: $action.scrollDistance)\n    }\n}\n\nextension ButtonMappingActionScroll {\n    struct DistanceInput: View {\n        @Binding var distance: Scheme.Scrolling.Distance\n\n        typealias Mode = Scheme.Scrolling.Distance.Mode\n\n        var body: some View {\n            HStack {\n                Picker(String(\"\"), selection: $distance.mode) {\n                    ForEach(Mode.allCases) {\n                        $0.label.tag($0)\n                    }\n                }\n                .modifier(PickerViewModifier())\n                .fixedSize()\n\n                switch $distance.mode.wrappedValue {\n                case .byLines:\n                    Slider(\n                        value: $distance.lineCount,\n                        in: 0 ... 10,\n                        step: 1\n                    ) {} minimumValueLabel: {\n                        Text(verbatim: \"0\")\n                    } maximumValueLabel: {\n                        Text(verbatim: \"10\")\n                    }\n                    .labelsHidden()\n\n                case .byPixels:\n                    Slider(\n                        value: $distance.pixelCount,\n                        in: 0 ... 128\n                    ) {} minimumValueLabel: {\n                        Text(verbatim: \"0px\")\n                    } maximumValueLabel: {\n                        Text(verbatim: \"128px\")\n                    }\n                    .labelsHidden()\n                }\n            }\n            .padding(.bottom)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingAction/ScrollingDistance+Binding.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport SwiftUI\n\nextension Binding where Value == Scheme.Scrolling.Distance {\n    var mode: Binding<Scheme.Scrolling.Distance.Mode> {\n        Binding<Scheme.Scrolling.Distance.Mode>(\n            get: {\n                wrappedValue.mode\n            },\n            set: {\n                switch $0 {\n                case .byLines:\n                    wrappedValue = .line(3)\n                case .byPixels:\n                    wrappedValue = .pixel(36)\n                }\n            }\n        )\n    }\n\n    var lineCount: Binding<Double> {\n        Binding<Double>(\n            get: {\n                guard case let .line(value) = wrappedValue else {\n                    return 3\n                }\n\n                return Double(value)\n            },\n            set: {\n                wrappedValue = .line(Int($0))\n            }\n        )\n    }\n\n    var pixelCount: Binding<Double> {\n        Binding<Double>(\n            get: {\n                guard case let .pixel(value) = wrappedValue else {\n                    return 36\n                }\n\n                return value.asTruncatedDouble\n            },\n            set: {\n                wrappedValue = .pixel(Decimal($0).rounded(1))\n            }\n        )\n    }\n}\n\nextension Scheme.Scrolling.Distance.Mode {\n    @ViewBuilder\n    var label: some View {\n        switch self {\n        case .byLines:\n            Text(\"By Lines\")\n        case .byPixels:\n            Text(\"By Pixels\")\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingButtonRecorder.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport ObservationToken\nimport SwiftUI\n\nstruct ButtonMappingButtonRecorder: View {\n    @Binding var mapping: Scheme.Buttons.Mapping\n\n    var autoStartRecording = false\n\n    @ObservedObject private var settingsState = SettingsState.shared\n\n    @State private var recording = false {\n        didSet {\n            guard oldValue != recording else {\n                return\n            }\n            updateSharedRecordingState()\n            recordingUpdated()\n        }\n    }\n\n    @State private var recordingObservationToken: ObservationToken?\n    @State private var recordedButtonCancellable: AnyCancellable?\n\n    var body: some View {\n        Button {\n            recording.toggle()\n        } label: {\n            Group {\n                if recording {\n                    ButtonMappingButtonDescription(mapping: mapping, showPartial: true) {\n                        Text(settingsState.isPreparingVirtualButtonRecording ? \"Waiting for device…\" : \"Recording\")\n                    }\n                    .foregroundColor(.orange)\n                } else {\n                    ButtonMappingButtonDescription(mapping: mapping) {\n                        Text(\"Click to record\")\n                    }\n                }\n            }\n            .frame(maxWidth: .infinity)\n        }\n        .onAppear {\n            updateSharedRecordingState()\n            if autoStartRecording {\n                recording = true\n            }\n        }\n        .onDisappear {\n            cancelObservation()\n            recording = false\n            updateSharedRecordingState(force: false)\n        }\n    }\n\n    private func updateSharedRecordingState(force: Bool? = nil) {\n        let shouldRecord = force ?? recording\n        if shouldRecord {\n            settingsState.beginVirtualButtonRecordingPreparation(for: logitechMonitorDeviceIDs())\n        } else {\n            settingsState.endVirtualButtonRecordingPreparation()\n        }\n\n        settingsState.recording = shouldRecord\n    }\n\n    private func recordingUpdated() {\n        if let recordingObservationToken {\n            recordingObservationToken.cancel()\n            self.recordingObservationToken = nil\n        }\n        recordedButtonCancellable?.cancel()\n        recordedButtonCancellable = nil\n\n        if recording {\n            mapping.modifierFlags = []\n            mapping.button = nil\n            mapping.repeat = nil\n            mapping.hold = nil\n            mapping.scroll = nil\n            startEventObservation()\n        }\n    }\n\n    private func startEventObservation() {\n        recordingObservationToken = try? EventTap.observe([\n            .flagsChanged,\n            .scrollWheel,\n            .leftMouseDown, .leftMouseUp,\n            .rightMouseDown, .rightMouseUp,\n            .otherMouseDown, .otherMouseUp\n        ], place: .tailAppendEventTap) { _, event in\n            eventReceived(event)\n        }\n\n        if recordingObservationToken == nil {\n            recording = false\n            return\n        }\n\n        settingsState.recordedVirtualButtonEvent = nil\n\n        // Observe Logitech control presses communicated via SettingsState\n        // (no synthetic CGEvent needed — the HID++ protocol detects presses directly)\n        recordedButtonCancellable = settingsState\n            .$recordedVirtualButtonEvent\n            .compactMap(\\.self)\n            .receive(on: DispatchQueue.main)\n            .sink { event in\n                virtualButtonReceived(event)\n            }\n    }\n\n    private func cancelObservation() {\n        recordedButtonCancellable?.cancel()\n        recordedButtonCancellable = nil\n    }\n\n    private func logitechMonitorDeviceIDs() -> Set<Int32> {\n        guard let currentDevice = DeviceState.shared.currentDeviceRef?.value,\n              currentDevice.hasLogitechControlsMonitor else {\n            return []\n        }\n\n        return [currentDevice.id]\n    }\n\n    private func virtualButtonReceived(_ event: SettingsState.RecordedVirtualButtonEvent) {\n        mapping.button = event.button\n        mapping.modifierFlags = event.modifierFlags\n        settingsState.recordedVirtualButtonEvent = nil\n        recording = false\n    }\n\n    private func eventReceived(_ event: CGEvent) -> CGEvent? {\n        mapping.button = nil\n        mapping.scroll = nil\n        mapping.modifierFlags = event.flags\n\n        switch event.type {\n        case .flagsChanged:\n            return nil\n\n        case .leftMouseDown, .rightMouseDown, .otherMouseDown:\n            mapping.button = .mouse(Int(event.getIntegerValueField(.mouseEventButtonNumber)))\n            return nil\n\n        case .leftMouseUp, .rightMouseUp, .otherMouseUp:\n            mapping.button = .mouse(Int(event.getIntegerValueField(.mouseEventButtonNumber)))\n\n        case .scrollWheel:\n            let scrollWheelEventView = ScrollWheelEventView(event)\n            if scrollWheelEventView.deltaYSignum < 0 {\n                mapping.scroll = .down\n            } else if scrollWheelEventView.deltaYSignum > 0 {\n                mapping.scroll = .up\n            } else if scrollWheelEventView.deltaXSignum < 0 {\n                mapping.scroll = .right\n            } else if scrollWheelEventView.deltaXSignum > 0 {\n                mapping.scroll = .left\n            }\n\n        default:\n            break\n        }\n\n        recording = false\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingEditSheet.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingEditSheet: View {\n    @Binding var isPresented: Bool\n\n    @ObservedObject private var state: ButtonsSettingsState = .shared\n\n    @Binding var mapping: Scheme.Buttons.Mapping\n    let completion: ((Scheme.Buttons.Mapping) -> Void)?\n\n    @State private var mode: Mode\n\n    init(\n        isPresented: Binding<Bool>,\n        mapping: Binding<Scheme.Buttons.Mapping>,\n        mode: Mode = .edit,\n        completion: ((Scheme.Buttons.Mapping) -> Void)?\n    ) {\n        _isPresented = isPresented\n        _mapping = mapping\n        self.completion = completion\n        self.mode = mode\n    }\n\n    var body: some View {\n        VStack(spacing: 20) {\n            Form {\n                Group {\n                    if mode == .edit {\n                        ButtonMappingButtonDescription<EmptyView>(mapping: mapping)\n                    } else {\n                        ButtonMappingButtonRecorder(\n                            mapping: $mapping,\n                            autoStartRecording: mode == .create\n                        )\n                    }\n                }\n                .formLabel(Text(\"Trigger\"))\n\n                if !valid, conflicted {\n                    Text(\"The trigger is already assigned.\")\n                        .foregroundColor(.red)\n                        .controlSize(.small)\n                        .fixedSize(horizontal: false, vertical: true)\n                }\n\n                if !valid, mapping.button?.mouseButtonNumber == 0, mapping.modifierFlags.isEmpty {\n                    Text(\"Assigning an action to the left button without any modifier keys is not allowed.\")\n                        .foregroundColor(.red)\n                        .controlSize(.small)\n                        .fixedSize(horizontal: false, vertical: true)\n                }\n\n                if valid {\n                    ButtonMappingAction(action: $mapping.action.default(.arg0(.auto)))\n\n                    if mapping.button != nil {\n                        if mapping.isKeyPressAction {\n                            Picker(\"While pressed\", selection: $mapping.keyPressBehavior) {\n                                Text(\"Send once on release\").tag(Scheme.Buttons.Mapping.KeyPressBehavior.sendOnRelease)\n                                Text(\"Repeat\").tag(Scheme.Buttons.Mapping.KeyPressBehavior.repeat)\n                                Text(\"Hold keys while pressed\").tag(\n                                    Scheme.Buttons.Mapping.KeyPressBehavior.holdWhilePressed\n                                )\n                            }\n                            .modifier(PickerViewModifier())\n                        } else {\n                            Toggle(isOn: $mapping.repeat.default(false)) {\n                                Text(\"Repeat on hold\")\n                            }\n                        }\n                    }\n                }\n            }\n\n            HStack(spacing: 8) {\n                Spacer()\n\n                Button(\"Cancel\") {\n                    isPresented = false\n                }\n\n                Button(mode == .create ? \"Create\" : \"OK\") {\n                    isPresented = false\n                    mode = .edit\n                    completion?(mapping)\n                }\n                .disabled(!valid)\n                .asDefaultAction()\n            }\n        }\n        .padding()\n        .frame(width: 400)\n    }\n}\n\nextension ButtonMappingEditSheet {\n    enum Mode {\n        case edit, create\n    }\n\n    var conflicted: Bool {\n        guard mode == .create else {\n            return false\n        }\n\n        return !state.mappings.allSatisfy { !mapping.conflicted(with: $0) }\n    }\n\n    var valid: Bool {\n        mapping.valid && !conflicted\n    }\n}\n\nprivate extension Scheme.Buttons.Mapping {\n    var isKeyPressAction: Bool {\n        guard case .arg1(.keyPress) = action else {\n            return false\n        }\n\n        return true\n    }\n}\n\nprivate extension Binding where Value == Scheme.Buttons.Mapping {\n    var keyPressBehavior: Binding<Scheme.Buttons.Mapping.KeyPressBehavior> {\n        Binding<Scheme.Buttons.Mapping.KeyPressBehavior>(\n            get: {\n                wrappedValue.keyPressBehavior\n            },\n            set: {\n                wrappedValue.keyPressBehavior = $0\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonMappingsSection/ButtonMappingsSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonMappingsSection: View {\n    @ObservedObject private var state: ButtonsSettingsState = .shared\n\n    @State private var selection: Set<Scheme.Buttons.Mapping> = []\n\n    @State private var showAddSheet = false\n    @State private var mappingToAdd: Scheme.Buttons.Mapping = .init()\n\n    var body: some View {\n        Section {\n            if #available(macOS 13.0, *) {\n                if !state.mappings.isEmpty {\n                    List($state.mappings, id: \\.self, selection: $selection) { $mapping in\n                        ButtonMappingListItem(mapping: $mapping)\n                    }\n                }\n            } else {\n                List($state.mappings, id: \\.self, selection: $selection) { $mapping in\n                    ButtonMappingListItem(mapping: $mapping)\n                }\n                .frame(height: 200)\n            }\n        } header: {\n            Text(\"Assign actions to mouse buttons\")\n        } footer: {\n            HStack(spacing: 4) {\n                Button {\n                    mappingToAdd = .init()\n                    showAddSheet.toggle()\n                } label: {\n                    VStack {\n                        Image(\"Plus\")\n                    }\n                    .frame(width: 16, height: 16)\n                }\n                .buttonStyle(.plain)\n                .sheet(isPresented: $showAddSheet) {\n                    ButtonMappingEditSheet(\n                        isPresented: $showAddSheet,\n                        mapping: $mappingToAdd,\n                        mode: .create\n                    ) { mapping in\n                        state.appendMapping(mapping)\n                    }\n                }\n\n                Button {\n                    state.mappings = state.mappings.filter { !selection.contains($0) }\n                    selection = []\n                } label: {\n                    VStack {\n                        Image(\"Minus\")\n                    }\n                    .frame(width: 16, height: 16)\n                }\n                .buttonStyle(.plain)\n                .disabled(selection.isEmpty)\n            }\n        }\n        .modifier(SectionViewModifier())\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonsSettings.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ButtonsSettings: View {\n    var body: some View {\n        DetailView {\n            Form {\n                UniversalBackForwardSection()\n\n                SwitchPrimaryAndSecondaryButtonsSection()\n\n                ClickDebouncingSection()\n\n                AutoScrollSection()\n\n                GestureButtonSection()\n\n                ButtonMappingsSection()\n            }\n            .modifier(FormViewModifier())\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ButtonsSettingsState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\nimport PublishedObject\nimport SwiftUI\n\nclass ButtonsSettingsState: ObservableObject {\n    static let shared: ButtonsSettingsState = .init()\n\n    @PublishedObject private var schemeState = SchemeState.shared\n    var scheme: Scheme {\n        get { schemeState.scheme }\n        set { schemeState.scheme = newValue }\n    }\n\n    var mergedScheme: Scheme {\n        schemeState.mergedScheme\n    }\n}\n\nextension ButtonsSettingsState {\n    private var defaultAutoScrollModes: [Scheme.Buttons.AutoScroll.Mode] {\n        [.toggle]\n    }\n\n    private var defaultAutoScrollTrigger: Scheme.Buttons.Mapping {\n        var mapping = Scheme.Buttons.Mapping()\n        mapping.button = .mouse(Int(CGMouseButton.center.rawValue))\n        return mapping\n    }\n\n    var universalBackForward: Bool {\n        get {\n            mergedScheme.buttons.universalBackForward ?? .none != .none\n        }\n        set {\n            scheme.buttons.universalBackForward = .some(newValue ? .both : .none)\n        }\n    }\n\n    var switchPrimaryAndSecondaryButtons: Bool {\n        get {\n            mergedScheme.buttons.switchPrimaryButtonAndSecondaryButtons ?? false\n        }\n        set {\n            scheme.buttons.switchPrimaryButtonAndSecondaryButtons = newValue\n        }\n    }\n\n    var clickDebouncingEnabled: Bool {\n        get {\n            mergedScheme.buttons.clickDebouncing.timeout ?? 0 > 0\n        }\n        set {\n            scheme.buttons.clickDebouncing.timeout = newValue ? 50 : 0\n        }\n    }\n\n    var clickDebouncingTimeout: Int {\n        get {\n            mergedScheme.buttons.clickDebouncing.timeout ?? 0\n        }\n        set {\n            scheme.buttons.clickDebouncing.timeout = newValue\n        }\n    }\n\n    var clickDebouncingTimeoutInDouble: Double {\n        get {\n            Double(clickDebouncingTimeout)\n        }\n        set {\n            clickDebouncingTimeout = newValue <= 10 ? Int(round(newValue)) : Int(round(newValue / 10)) * 10\n        }\n    }\n\n    var clickDebouncingTimeoutFormatter: NumberFormatter {\n        let formatter = NumberFormatter()\n        formatter.numberStyle = NumberFormatter.Style.decimal\n        formatter.roundingMode = NumberFormatter.RoundingMode.halfUp\n        formatter.maximumFractionDigits = 0\n        formatter.thousandSeparator = \"\"\n        formatter.minimum = 5\n        formatter.maximum = 500\n        return formatter\n    }\n\n    var clickDebouncingResetTimerOnMouseUp: Bool {\n        get {\n            mergedScheme.buttons.clickDebouncing.resetTimerOnMouseUp ?? false\n        }\n        set {\n            scheme.buttons.clickDebouncing.resetTimerOnMouseUp = newValue\n        }\n    }\n\n    func clickDebouncingButtonEnabledBinding(for button: CGMouseButton) -> Binding<Bool> {\n        Binding<Bool>(\n            get: { [self] in\n                (mergedScheme.buttons.clickDebouncing.buttons ?? []).contains(button)\n            },\n            set: { [self] newValue in\n                let buttons = mergedScheme.buttons.clickDebouncing.buttons ?? []\n                if newValue {\n                    scheme.buttons.clickDebouncing.buttons = buttons + [button]\n                } else {\n                    scheme.buttons.clickDebouncing.buttons = buttons.filter { $0 != button }\n                }\n            }\n        )\n    }\n\n    var autoScrollEnabled: Bool {\n        get {\n            mergedScheme.buttons.autoScroll.enabled ?? false\n        }\n        set {\n            guard newValue != autoScrollEnabled else {\n                return\n            }\n\n            if newValue {\n                scheme.buttons.autoScroll.enabled = true\n                if scheme.buttons.autoScroll.trigger == nil {\n                    scheme.buttons.autoScroll.trigger = defaultAutoScrollTrigger\n                }\n                if scheme.buttons.autoScroll.modes == nil {\n                    scheme.buttons.autoScroll.modes = defaultAutoScrollModes\n                }\n                if scheme.buttons.autoScroll.speed == nil {\n                    scheme.buttons.autoScroll.speed = 1\n                }\n                if scheme.buttons.autoScroll.preserveNativeMiddleClick == nil {\n                    scheme.buttons.autoScroll.preserveNativeMiddleClick = true\n                }\n            } else {\n                scheme.buttons.autoScroll.enabled = false\n            }\n\n            GlobalEventTap.shared.stop()\n            GlobalEventTap.shared.start()\n        }\n    }\n\n    var autoScrollModes: [Scheme.Buttons.AutoScroll.Mode] {\n        get {\n            mergedScheme.buttons.autoScroll.normalizedModes\n        }\n        set {\n            let orderedModes = Scheme.Buttons.AutoScroll.Mode.allCases.filter { newValue.contains($0) }\n            scheme.buttons.autoScroll.modes = orderedModes.isEmpty ? defaultAutoScrollModes : orderedModes\n        }\n    }\n\n    var autoScrollToggleModeEnabled: Bool {\n        get {\n            autoScrollModes.contains(.toggle)\n        }\n        set {\n            var modes = Set(autoScrollModes)\n            if newValue {\n                modes.insert(.toggle)\n            } else {\n                modes.remove(.toggle)\n            }\n            autoScrollModes = Array(modes)\n        }\n    }\n\n    var autoScrollHoldModeEnabled: Bool {\n        get {\n            autoScrollModes.contains(.hold)\n        }\n        set {\n            var modes = Set(autoScrollModes)\n            if newValue {\n                modes.insert(.hold)\n            } else {\n                modes.remove(.hold)\n            }\n            autoScrollModes = Array(modes)\n        }\n    }\n\n    var autoScrollSpeed: Double {\n        get {\n            mergedScheme.buttons.autoScroll.speed?.asTruncatedDouble ?? 1\n        }\n        set {\n            scheme.buttons.autoScroll.speed = Decimal(newValue).rounded(1)\n        }\n    }\n\n    var autoScrollSpeedText: String {\n        String(format: \"%.1fx\", autoScrollSpeed)\n    }\n\n    var autoScrollPreserveNativeMiddleClick: Bool {\n        get {\n            mergedScheme.buttons.autoScroll.preserveNativeMiddleClick ?? true\n        }\n        set {\n            scheme.buttons.autoScroll.preserveNativeMiddleClick = newValue\n        }\n    }\n\n    var autoScrollTrigger: Scheme.Buttons.Mapping {\n        get {\n            mergedScheme.buttons.autoScroll.trigger ?? defaultAutoScrollTrigger\n        }\n        set {\n            var trigger = newValue\n            trigger.action = nil\n            trigger.repeat = nil\n            trigger.hold = nil\n            trigger.scroll = nil\n            scheme.buttons.autoScroll.trigger = trigger\n        }\n    }\n\n    var autoScrollTriggerBinding: Binding<Scheme.Buttons.Mapping> {\n        Binding(\n            get: { [self] in\n                autoScrollTrigger\n            },\n            set: { [self] in\n                autoScrollTrigger = $0\n            }\n        )\n    }\n\n    var autoScrollTriggerValid: Bool {\n        autoScrollTrigger.valid\n    }\n\n    var autoScrollUsesPlainMiddleClick: Bool {\n        let trigger = autoScrollTrigger\n        return trigger.button == .mouse(Int(CGMouseButton.center.rawValue)) && trigger.modifierFlags.isEmpty\n    }\n\n    var autoScrollPreserveNativeMiddleClickAvailable: Bool {\n        autoScrollUsesPlainMiddleClick && autoScrollToggleModeEnabled\n    }\n\n    var mappings: [Scheme.Buttons.Mapping] {\n        get { scheme.buttons.mappings ?? [] }\n        set { scheme.buttons.mappings = newValue }\n    }\n\n    func appendMapping(_ mapping: Scheme.Buttons.Mapping) {\n        mappings = (mappings + [mapping]).sorted()\n    }\n\n    private var defaultGestureTrigger: Scheme.Buttons.Mapping {\n        var mapping = Scheme.Buttons.Mapping()\n        mapping.button = .mouse(Int(CGMouseButton.center.rawValue))\n        return mapping\n    }\n\n    var gestureEnabled: Bool {\n        get {\n            mergedScheme.buttons.gesture.enabled ?? false\n        }\n        set {\n            guard newValue != gestureEnabled else {\n                return\n            }\n\n            if newValue {\n                scheme.buttons.gesture.enabled = true\n                if scheme.buttons.gesture.trigger == nil {\n                    scheme.buttons.gesture.trigger = defaultGestureTrigger\n                }\n                if scheme.buttons.gesture.threshold == nil {\n                    scheme.buttons.gesture.threshold = 50\n                }\n                if scheme.buttons.gesture.actions.left == nil {\n                    scheme.buttons.gesture.actions.left = .spaceLeft\n                }\n                if scheme.buttons.gesture.actions.right == nil {\n                    scheme.buttons.gesture.actions.right = .spaceRight\n                }\n                if scheme.buttons.gesture.actions.up == nil {\n                    scheme.buttons.gesture.actions.up = .missionControl\n                }\n                if scheme.buttons.gesture.actions.down == nil {\n                    scheme.buttons.gesture.actions.down = .appExpose\n                }\n            } else {\n                scheme.buttons.gesture.enabled = false\n            }\n\n            GlobalEventTap.shared.stop()\n            GlobalEventTap.shared.start()\n        }\n    }\n\n    var gestureTrigger: Scheme.Buttons.Mapping {\n        get {\n            mergedScheme.buttons.gesture.trigger ?? defaultGestureTrigger\n        }\n        set {\n            var trigger = newValue\n            trigger.action = nil\n            trigger.repeat = nil\n            trigger.hold = nil\n            trigger.scroll = nil\n            scheme.buttons.gesture.trigger = trigger\n        }\n    }\n\n    var gestureTriggerBinding: Binding<Scheme.Buttons.Mapping> {\n        Binding(\n            get: { [self] in\n                gestureTrigger\n            },\n            set: { [self] in\n                gestureTrigger = $0\n            }\n        )\n    }\n\n    var gestureTriggerValid: Bool {\n        gestureTrigger.valid\n    }\n\n    var gestureThreshold: Int {\n        get {\n            mergedScheme.buttons.gesture.threshold ?? 50\n        }\n        set {\n            scheme.buttons.gesture.threshold = newValue\n        }\n    }\n\n    var gestureThresholdDouble: Double {\n        get {\n            Double(gestureThreshold)\n        }\n        set {\n            gestureThreshold = Int(round(newValue / 5)) * 5\n        }\n    }\n\n    var gestureActionLeft: Scheme.Buttons.Gesture.GestureAction {\n        get {\n            mergedScheme.buttons.gesture.actions.left ?? .spaceLeft\n        }\n        set {\n            scheme.buttons.gesture.actions.left = newValue\n        }\n    }\n\n    var gestureActionRight: Scheme.Buttons.Gesture.GestureAction {\n        get {\n            mergedScheme.buttons.gesture.actions.right ?? .spaceRight\n        }\n        set {\n            scheme.buttons.gesture.actions.right = newValue\n        }\n    }\n\n    var gestureActionUp: Scheme.Buttons.Gesture.GestureAction {\n        get {\n            mergedScheme.buttons.gesture.actions.up ?? .missionControl\n        }\n        set {\n            scheme.buttons.gesture.actions.up = newValue\n        }\n    }\n\n    var gestureActionDown: Scheme.Buttons.Gesture.GestureAction {\n        get {\n            mergedScheme.buttons.gesture.actions.down ?? .appExpose\n        }\n        set {\n            scheme.buttons.gesture.actions.down = newValue\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/ClickDebouncingSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ClickDebouncingSection: View {\n    @ObservedObject var state: ButtonsSettingsState = .shared\n\n    var body: some View {\n        Section {\n            Toggle(isOn: $state.clickDebouncingEnabled.animation()) {\n                withDescription {\n                    Text(\"Debounce button clicks\")\n                    Text(\n                        \"Ignore rapid clicks within a certain time period.\"\n                    )\n                }\n            }\n\n            if state.clickDebouncingEnabled {\n                HStack(spacing: 5) {\n                    Slider(\n                        value: $state.clickDebouncingTimeoutInDouble,\n                        in: 5 ... 500\n                    )\n                    .labelsHidden()\n                    TextField(\n                        String(\"\"),\n                        value: $state.clickDebouncingTimeout,\n                        formatter: state.clickDebouncingTimeoutFormatter\n                    )\n                    .labelsHidden()\n                    .textFieldStyle(.roundedBorder)\n                    .multilineTextAlignment(.trailing)\n                    .frame(width: 60)\n                    Text(\"ms\")\n                }\n\n                Toggle(isOn: $state.clickDebouncingResetTimerOnMouseUp.animation()) {\n                    Text(\"Reset timer on mouse up\")\n                }\n\n                VStack(alignment: .leading) {\n                    HStack(spacing: 16) {\n                        Toggle(\"Left button\", isOn: state.clickDebouncingButtonEnabledBinding(for: .left))\n                            .fixedSize()\n                        Toggle(\"Right button\", isOn: state.clickDebouncingButtonEnabledBinding(for: .right))\n                            .fixedSize()\n                        Toggle(\"Middle button\", isOn: state.clickDebouncingButtonEnabledBinding(for: .center))\n                            .fixedSize()\n                    }\n                    .toggleStyle(.checkbox)\n\n                    HStack(spacing: 16) {\n                        Toggle(\"Back button\", isOn: state.clickDebouncingButtonEnabledBinding(for: .back))\n                            .fixedSize()\n                        Toggle(\"Forward button\", isOn: state.clickDebouncingButtonEnabledBinding(for: .forward))\n                            .fixedSize()\n                    }\n                    .toggleStyle(.checkbox)\n                }\n            }\n        }\n        .modifier(SectionViewModifier())\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/GestureButtonSection/GestureActionPicker.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct GestureActionPicker: View {\n    typealias GestureAction = Scheme.Buttons.Gesture.GestureAction\n\n    let label: LocalizedStringKey\n    @Binding var selection: GestureAction\n\n    var body: some View {\n        Picker(label, selection: $selection) {\n            Text(\"None\").tag(GestureAction.none)\n            Text(\"Previous Space\").tag(GestureAction.spaceLeft)\n            Text(\"Next Space\").tag(GestureAction.spaceRight)\n            Text(\"Mission Control\").tag(GestureAction.missionControl)\n            Text(\"App Expose\").tag(GestureAction.appExpose)\n            Text(\"Show Desktop\").tag(GestureAction.showDesktop)\n            Text(\"Launchpad\").tag(GestureAction.launchpad)\n        }\n        .modifier(PickerViewModifier())\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/GestureButtonSection/GestureButtonSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct GestureButtonSection: View {\n    @ObservedObject var state: ButtonsSettingsState = .shared\n\n    var isMouseDevice: Bool {\n        DeviceState.shared.currentDeviceRef?.value?.category == .mouse\n    }\n\n    var body: some View {\n        if isMouseDevice {\n            Section {\n                Toggle(isOn: $state.gestureEnabled.animation()) {\n                    withDescription {\n                        Text(\"Enable gesture button\")\n                        Text(\n                            \"Press and hold a button while dragging to trigger gestures like switching desktop spaces or opening Mission Control.\"\n                        )\n                    }\n                }\n\n                if state.gestureEnabled {\n                    VStack(alignment: .leading, spacing: 8) {\n                        Text(\"Trigger\")\n                            .font(.headline)\n\n                        ButtonMappingButtonRecorder(\n                            mapping: state.gestureTriggerBinding\n                        )\n\n                        if !state.gestureTriggerValid {\n                            Text(\"Choose a mouse button trigger. Left click without modifier keys is not allowed.\")\n                                .foregroundColor(.red)\n                                .controlSize(.small)\n                                .fixedSize(horizontal: false, vertical: true)\n                        }\n                    }\n\n                    VStack(alignment: .leading, spacing: 4) {\n                        HStack {\n                            Text(\"Threshold\")\n                            Spacer()\n                            Text(\"\\(state.gestureThreshold) pixels\")\n                                .foregroundColor(.secondary)\n                        }\n                        Slider(value: $state.gestureThresholdDouble, in: 20 ... 200, step: 5)\n                    }\n\n                    Divider()\n\n                    Text(\"Gesture Actions\")\n                        .font(.headline)\n\n                    GestureActionPicker(\n                        label: \"Swipe left\",\n                        selection: $state.gestureActionLeft\n                    )\n\n                    GestureActionPicker(\n                        label: \"Swipe right\",\n                        selection: $state.gestureActionRight\n                    )\n\n                    GestureActionPicker(\n                        label: \"Swipe up\",\n                        selection: $state.gestureActionUp\n                    )\n\n                    GestureActionPicker(\n                        label: \"Swipe down\",\n                        selection: $state.gestureActionDown\n                    )\n\n                    Text(\n                        \"Hold the button and drag to trigger gestures. Drag at least \\(state.gestureThreshold) pixels in one direction.\"\n                    )\n                    .font(.caption)\n                    .foregroundColor(.secondary)\n                    .padding(.top, 8)\n                }\n            }\n            .modifier(SectionViewModifier())\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/SwitchPrimaryAndSecondaryButtonsSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct SwitchPrimaryAndSecondaryButtonsSection: View {\n    @ObservedObject var state: ButtonsSettingsState = .shared\n\n    var body: some View {\n        Section {\n            Toggle(isOn: $state.switchPrimaryAndSecondaryButtons) {\n                Text(\"Switch primary and secondary buttons\")\n            }\n        }\n        .modifier(SectionViewModifier())\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ButtonsSettings/UniversalBackForwardSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct UniversalBackForwardSection: View {\n    @ObservedObject var state: ButtonsSettingsState = .shared\n\n    var body: some View {\n        Section {\n            Toggle(isOn: $state.universalBackForward) {\n                withDescription {\n                    Text(\"Enable universal back and forward\")\n                    Text(\n                        \"Convert the back and forward side buttons to swiping gestures to allow universal back and forward functionality.\"\n                    )\n                }\n            }\n        }\n        .modifier(SectionViewModifier())\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/CheckForUpdatesView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Defaults\nimport Sparkle\nimport SwiftUI\n\nfinal class UpdaterViewModel: ObservableObject {\n    static let shared = UpdaterViewModel()\n\n    @Published var canCheckForUpdates = false\n\n    @Published var automaticallyChecksForUpdates = false {\n        didSet {\n            controller.updater.automaticallyChecksForUpdates = automaticallyChecksForUpdates\n        }\n    }\n\n    @Published var updateCheckInterval: TimeInterval = 604_800 {\n        didSet {\n            controller.updater.updateCheckInterval = updateCheckInterval\n        }\n    }\n\n    private let controller = AutoUpdateManager.shared.controller\n    private var subscriptions = Set<AnyCancellable>()\n\n    init() {\n        controller.updater\n            .publisher(for: \\.canCheckForUpdates)\n            .sink { value in\n                self.canCheckForUpdates = value\n            }\n            .store(in: &subscriptions)\n\n        controller.updater\n            .publisher(for: \\.automaticallyChecksForUpdates)\n            .sink { value in\n                guard value != self.automaticallyChecksForUpdates else {\n                    return\n                }\n                self.automaticallyChecksForUpdates = value\n            }\n            .store(in: &subscriptions)\n\n        controller.updater\n            .publisher(for: \\.updateCheckInterval)\n            .sink { value in\n                guard value != self.updateCheckInterval else {\n                    return\n                }\n                self.updateCheckInterval = value\n            }\n            .store(in: &subscriptions)\n    }\n\n    func checkForUpdates() {\n        controller.checkForUpdates(nil)\n    }\n}\n\nstruct CheckForUpdatesView: View {\n    @ObservedObject var updaterViewModel = UpdaterViewModel.shared\n    @Default(.betaChannelOn) var betaChannelOn\n\n    var body: some View {\n        Text(\"Version: \\(LinearMouse.appVersion)\")\n            .foregroundColor(.secondary)\n\n        Toggle(isOn: $updaterViewModel.automaticallyChecksForUpdates.animation()) {\n            Text(\"Check for updates automatically\")\n        }\n\n        if updaterViewModel.automaticallyChecksForUpdates {\n            Picker(\"Update check interval\", selection: $updaterViewModel.updateCheckInterval) {\n                Text(\"Daily\").tag(TimeInterval(86_400))\n                Text(\"Weekly\").tag(TimeInterval(604_800))\n                Text(\"Monthly\").tag(TimeInterval(2_629_800))\n            }\n            .modifier(PickerViewModifier())\n        }\n\n        Toggle(isOn: $betaChannelOn.animation()) {\n            withDescription {\n                Text(\"Receive beta updates\")\n                if betaChannelOn {\n                    Text(\"Thank you for participating in the beta test.\")\n                }\n            }\n        }\n\n        Button(\"Check for Updates…\", action: updaterViewModel.checkForUpdates)\n            .disabled(!updaterViewModel.canCheckForUpdates)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/DetailView/DetailView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DetailView<T: View>: View {\n    var schemeSpecific = true\n    var content: () -> T\n\n    @ObservedObject var schemeState = SchemeState.shared\n\n    var body: some View {\n        VStack(alignment: .leading, spacing: 0) {\n            if schemeSpecific, !schemeState.isSchemeValid {\n                Text(\"No device selected.\")\n                    .frame(\n                        maxWidth: .infinity,\n                        maxHeight: .infinity\n                    )\n            } else {\n                content()\n            }\n        }\n        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Extensions/NSWindow.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nextension NSWindow {\n    func bringToFront() {\n        NSApplication.shared.activate(ignoringOtherApps: true)\n        makeKeyAndOrderFront(nil)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Extensions/View.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\n// https://gist.github.com/marcprux/afd2f80baa5b6d60865182a828e83586\n\n/// Alignment guide for aligning a text field in a `Form`.\n/// Thanks for Jim Dovey  https://developer.apple.com/forums/thread/126268\nextension HorizontalAlignment {\n    private enum ControlAlignment: AlignmentID {\n        static func defaultValue(in context: ViewDimensions) -> CGFloat {\n            context[HorizontalAlignment.center]\n        }\n    }\n\n    static let controlAlignment = HorizontalAlignment(ControlAlignment.self)\n}\n\npublic extension View {\n    /// Attaches a label to this view for laying out in a `Form`\n    /// - Parameter view: the label view to use\n    /// - Returns: an `HStack` with an alignment guide for placing in a form\n    func formLabel<V: View>(_ view: V) -> some View {\n        HStack {\n            view\n            self\n                .alignmentGuide(.controlAlignment) { $0[.leading] }\n        }\n        .alignmentGuide(.leading) { $0[.controlAlignment] }\n    }\n}\n\nextension View {\n    func asDefaultAction() -> some View {\n        if #available(macOS 11, *) {\n            return keyboardShortcut(.defaultAction)\n        }\n        return self\n    }\n\n    func asCancelAction() -> some View {\n        if #available(macOS 11, *) {\n            return keyboardShortcut(.cancelAction)\n        }\n        return self\n    }\n\n    func sheetPrimaryActionStyle() -> some View {\n        modifier(SheetActionButtonModifier(kind: .primary))\n    }\n\n    func sheetSecondaryActionStyle() -> some View {\n        modifier(SheetActionButtonModifier(kind: .secondary))\n    }\n\n    func sheetDestructiveActionStyle() -> some View {\n        modifier(SheetActionButtonModifier(kind: .destructive))\n    }\n}\n\nprivate enum SheetActionButtonKind {\n    case primary\n    case secondary\n    case destructive\n}\n\nprivate struct SheetActionButtonModifier: ViewModifier {\n    let kind: SheetActionButtonKind\n\n    func body(content: Content) -> some View {\n        if #available(macOS 12.0, *) {\n            if kind == .primary {\n                shapedContent(styledContent(content))\n                    .buttonStyle(.borderedProminent)\n            } else {\n                shapedContent(styledContent(content))\n                    .buttonStyle(.bordered)\n            }\n        } else {\n            legacyStyledContent(content)\n        }\n    }\n\n    private func styledContent(_ content: Content) -> some View {\n        let base = sizeAdjustedContent(content)\n\n        if #available(macOS 12.0, *), kind == .destructive {\n            return AnyView(base.tint(.red))\n        }\n        return AnyView(base)\n    }\n\n    private func shapedContent(_ content: some View) -> some View {\n        if #available(macOS 14.0, *) {\n            return AnyView(content.buttonBorderShape(.capsule))\n        } else {\n            return AnyView(content)\n        }\n    }\n\n    private func legacyStyledContent(_ content: Content) -> some View {\n        let base = sizeAdjustedContent(content)\n\n        if kind == .destructive {\n            return AnyView(base.foregroundColor(.red))\n        }\n        return AnyView(base)\n    }\n\n    private func sizeAdjustedContent(_ content: Content) -> some View {\n        if #available(macOS 11.0, *) {\n            return AnyView(content.controlSize(.large))\n        } else {\n            return AnyView(content.controlSize(.regular))\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/GeneralSettings/ConfigurationSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ConfigurationSection: View {\n    @ObservedObject var configurationState = ConfigurationState.shared\n\n    var body: some View {\n        Section {\n            HStack {\n                Button(\"Reload Config\") {\n                    configurationState.load()\n                }\n                .disabled(configurationState.loading)\n\n                Button(\"Reveal Config in Finder…\") {\n                    configurationState.revealInFinder()\n                }\n            }\n        }\n        .modifier(SectionViewModifier())\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/GeneralSettings/GeneralSettings.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\nimport LaunchAtLogin\nimport SwiftUI\n\nstruct GeneralSettings: View {\n    @Default(.showInMenuBar) var showInMenuBar\n    @Default(.menuBarBatteryDisplayMode) var menuBarBatteryDisplayMode\n    @Default(.showInDock) var showInDock\n    @Default(.bypassEventsFromOtherApplications) var bypassEventsFromOtherApplications\n\n    var body: some View {\n        DetailView(schemeSpecific: false) {\n            Form {\n                Section {\n                    Toggle(isOn: $showInMenuBar.animation()) {\n                        withDescription {\n                            Text(\"Show in menu bar\")\n                            if !showInMenuBar {\n                                Text(\"To show the settings, launch \\(LinearMouse.appName) again.\")\n                            }\n                        }\n                    }\n\n                    if showInMenuBar {\n                        Picker(\"Show current battery\", selection: $menuBarBatteryDisplayMode.animation()) {\n                            Text(\"Off\").tag(MenuBarBatteryDisplayMode.off)\n                            batteryThresholdText(5).tag(MenuBarBatteryDisplayMode.below5)\n                            batteryThresholdText(10).tag(MenuBarBatteryDisplayMode.below10)\n                            batteryThresholdText(15).tag(MenuBarBatteryDisplayMode.below15)\n                            batteryThresholdText(20).tag(MenuBarBatteryDisplayMode.below20)\n                            Text(\"Always show\").tag(MenuBarBatteryDisplayMode.always)\n                        }\n                        .padding(.leading, 20)\n                        .modifier(PickerViewModifier())\n                    }\n\n                    Toggle(isOn: $showInDock) {\n                        Text(\"Show in Dock\")\n                    }\n                }\n                .modifier(SectionViewModifier())\n\n                Section {\n                    LaunchAtLogin.Toggle {\n                        Text(\"Start at login\")\n                    }\n                }\n                .modifier(SectionViewModifier())\n\n                Section {\n                    Toggle(isOn: $bypassEventsFromOtherApplications) {\n                        withDescription {\n                            Text(\"Bypass events from other applications\")\n                            Text(\n                                \"If enabled, \\(LinearMouse.appName) will not modify events sent by other applications, such as Logi Options+.\"\n                            )\n                        }\n                    }\n                }\n                .modifier(SectionViewModifier())\n\n                ConfigurationSection()\n\n                Section {\n                    CheckForUpdatesView()\n                }\n                .modifier(SectionViewModifier())\n\n                LoggingSection()\n\n                Section {\n                    HyperLink(URLs.homepage) {\n                        HStack(alignment: .firstTextBaseline, spacing: 5) {\n                            Text(verbatim: \"🏡\")\n                            Text(\"Homepage\")\n                        }\n                    }\n                    HyperLink(URLs.bugReport) {\n                        HStack(alignment: .firstTextBaseline, spacing: 5) {\n                            Text(verbatim: \"🐛\")\n                            Text(\"Bug report\")\n                        }\n                    }\n                    HyperLink(URLs.featureRequest) {\n                        HStack(alignment: .firstTextBaseline, spacing: 5) {\n                            Text(verbatim: \"✍🏻\")\n                            Text(\"Feature request\")\n                        }\n                    }\n                    HyperLink(URLs.donate) {\n                        HStack(alignment: .firstTextBaseline, spacing: 5) {\n                            Text(verbatim: \"❤️\")\n                            Text(\"Donate\")\n                        }\n                    }\n                }\n                .modifier(SectionViewModifier())\n                .frame(minHeight: 22)\n            }\n            .modifier(FormViewModifier())\n        }\n    }\n\n    private func batteryThresholdText(_ threshold: Int) -> Text {\n        Text(\"\\(formattedPercent(threshold)) or below\")\n    }\n}\n\nextension GeneralSettings {\n    enum URLs {\n        static func withEnvironmentParametersAppended(for url: URL) -> URL {\n            var osVersion = Foundation.ProcessInfo.processInfo.operatingSystemVersionString\n            if osVersion.hasPrefix(\"Version \") {\n                osVersion = String(osVersion.dropFirst(\"Version \".count))\n            }\n            osVersion = \"macOS \\(osVersion)\"\n            let linearMouseVersion = \"v\\(LinearMouse.appVersion)\"\n\n            var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!\n            var queryItems = components.queryItems ?? []\n            queryItems.append(contentsOf: [\n                .init(name: \"os\", value: osVersion),\n                .init(name: \"linearmouse\", value: linearMouseVersion)\n            ])\n            components.queryItems = queryItems\n\n            return components.url!\n        }\n\n        static var homepage: URL {\n            URL(string: \"https://linearmouse.app\")!\n        }\n\n        static var bugReport: URL {\n            withEnvironmentParametersAppended(for: URL(string: \"https://go.linearmouse.app/bug-report\")!)\n        }\n\n        static var featureRequest: URL {\n            withEnvironmentParametersAppended(for: URL(string: \"https://go.linearmouse.app/feature-request\")!)\n        }\n\n        static var donate: URL {\n            URL(string: \"https://go.linearmouse.app/donate\")!\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/GeneralSettings/LoggingSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\nimport OSLog\nimport SwiftUI\n\nstruct LoggingSection: View {\n    @Default(.verbosedLoggingOn) private var detailedLoggingOn\n\n    private let exportQueue = DispatchQueue(label: \"log-export\")\n    @State private var exporting = false\n\n    var body: some View {\n        Section {\n            Toggle(isOn: $detailedLoggingOn) {\n                withDescription {\n                    Text(\"Enable verbose logging\")\n                    Text(\n                        \"Enabling this option will log all input events, which may increase CPU usage while using \\(LinearMouse.appName), but can be useful for troubleshooting.\"\n                    )\n                }\n            }\n\n            VStack(alignment: .leading) {\n                Text(\"Export the logs for the last 5 minutes.\")\n                Text(\"If you are reporting a bug, it would be helpful to attach the logs.\")\n                    .controlSize(.small)\n                    .foregroundColor(.secondary)\n                    .fixedSize(horizontal: false, vertical: true)\n            }\n\n            Button(\"Export logs\") {\n                exportLogs()\n            }\n            .disabled(exporting)\n        }\n    }\n}\n\nextension LoggingSection {\n    private func level(_ level: OSLogEntryLog.Level) -> String {\n        switch level {\n        case .undefined:\n            return \"undefined\"\n        case .debug:\n            return \"debug\"\n        case .info:\n            return \"info\"\n        case .notice:\n            return \"notice\"\n        case .error:\n            return \"error\"\n        case .fault:\n            return \"fault\"\n        default:\n            return \"level:\\(level.rawValue)\"\n        }\n    }\n\n    func exportLogs() {\n        exportQueue.async {\n            exporting = true\n            defer { exporting = false }\n\n            do {\n                let logStore = try OSLogStore.local()\n                let position = logStore.position(timeIntervalSinceEnd: -5 * 60)\n                let predicate = NSPredicate(format: \"subsystem == '\\(LinearMouse.appBundleIdentifier)'\")\n                let entries = try logStore.getEntries(\n                    with: [],\n                    at: position,\n                    matching: predicate\n                )\n                let logs = entries\n                    .compactMap { $0 as? OSLogEntryLog }\n                    .filter { $0.subsystem == LinearMouse.appBundleIdentifier }\n                    .suffix(100_000)\n                    .map { \"\\($0.date)\\t\\(level($0.level))\\t\\($0.category)\\t\\($0.composedMessage)\\n\" }\n                    .joined()\n\n                let directory = FileManager.default.temporaryDirectory.appendingPathComponent(\n                    UUID().uuidString,\n                    isDirectory: true\n                )\n                try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)\n                let filePath = directory.appendingPathComponent(\"\\(LinearMouse.appName).log\")\n                try logs.write(to: filePath, atomically: true, encoding: .utf8)\n                NSWorkspace.shared.activateFileViewerSelecting([filePath.absoluteURL])\n            } catch {\n                DispatchQueue.main.async {\n                    let alert = NSAlert(error: error)\n                    alert.runModal()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/AppIndicator/AppIndicator.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct AppIndicator: View {\n    @State private var showAppPickerSheet = false\n\n    @ObservedObject private var schemeState: SchemeState = .shared\n\n    var body: some View {\n        Button {\n            showAppPickerSheet.toggle()\n        } label: {\n            Text(schemeState.currentAppName ?? NSLocalizedString(\"All Apps\", comment: \"\"))\n                .frame(maxWidth: 150)\n                .fixedSize()\n                .lineLimit(1)\n        }\n        .controlSize(.small)\n        .buttonStyle(SecondaryButtonStyle())\n        .sheet(isPresented: $showAppPickerSheet) {\n            AppPickerSheet(isPresented: $showAppPickerSheet)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/AppIndicator/AppPickerSheet/AppPicker.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct AppPicker: View {\n    @ObservedObject var state: AppPickerState = .shared\n\n    @Binding var selectedApp: AppTarget?\n\n    var pickerSelection: Binding<PickerSelection> {\n        Binding {\n            PickerSelection.value(selectedApp)\n        } set: { newValue in\n            switch newValue {\n            case let .value(value):\n                selectedApp = value\n\n            case .other:\n                selectedApp = nil\n\n                let panel = NSOpenPanel()\n                panel.allowsMultipleSelection = false\n                panel.canChooseDirectories = false\n                if #available(macOS 11.0, *) {\n                    panel.allowedContentTypes = [.applicationBundle]\n                }\n                guard panel.runModal() == .OK else {\n                    return\n                }\n\n                guard let url = panel.url else {\n                    return\n                }\n\n                guard let installedApp = try? readInstalledApp(at: url) else {\n                    return\n                }\n\n                selectedApp = .bundle(installedApp.bundleIdentifier)\n\n            case .otherExecutable:\n                selectedApp = nil\n\n                let panel = NSOpenPanel()\n                panel.allowsMultipleSelection = false\n                panel.canChooseDirectories = false\n                panel.allowsOtherFileTypes = true\n                panel.message = NSLocalizedString(\"Select an executable file\", comment: \"\")\n                guard panel.runModal() == .OK else {\n                    return\n                }\n\n                guard let url = panel.url else {\n                    return\n                }\n\n                selectedApp = .executable(url.path)\n            }\n        }\n    }\n\n    private var isSelectedAppInList: Bool {\n        switch selectedApp {\n        case .none:\n            return true\n\n        case let .bundle(bundleIdentifier):\n            return (state.configuredApps + state.installedApps)\n                .map(\\.bundleIdentifier)\n                .contains(bundleIdentifier)\n\n        case let .executable(path):\n            return state.configuredExecutables.contains(path)\n        }\n    }\n\n    var body: some View {\n        Picker(\"Configure for\", selection: pickerSelection) {\n            Text(\"All Apps\").frame(minHeight: 24).tag(PickerSelection.value(nil))\n\n            Section(header: Text(\"Configured\")) {\n                ForEach(state.configuredApps) { installedApp in\n                    AppPickerItem(installedApp: installedApp)\n                        .tag(PickerSelection.value(.bundle(installedApp.bundleIdentifier)))\n                }\n                ForEach(state.configuredExecutables, id: \\.self) { path in\n                    HStack(spacing: 8) {\n                        if #available(macOS 11.0, *) {\n                            Image(systemName: \"terminal\")\n                        }\n                        Text(URL(fileURLWithPath: path).lastPathComponent)\n                    }\n                    .tag(PickerSelection.value(.executable(path)))\n                }\n            }\n\n            Section(header: Text(\"Running\")) {\n                ForEach(state.runningApps) { installedApp in\n                    AppPickerItem(installedApp: installedApp)\n                        .tag(PickerSelection.value(.bundle(installedApp.bundleIdentifier)))\n                }\n            }\n\n            Section(header: Text(\"Installed\")) {\n                ForEach(state.otherApps) { installedApp in\n                    AppPickerItem(installedApp: installedApp)\n                        .tag(PickerSelection.value(.bundle(installedApp.bundleIdentifier)))\n                }\n            }\n\n            if !isSelectedAppInList {\n                switch selectedApp {\n                case .none:\n                    EmptyView()\n\n                case let .bundle(bundleIdentifier):\n                    if let installedApp = try? readInstalledApp(bundleIdentifier: bundleIdentifier) {\n                        AppPickerItem(installedApp: installedApp)\n                            .tag(PickerSelection.value(selectedApp))\n                    }\n\n                case let .executable(path):\n                    HStack(spacing: 8) {\n                        if #available(macOS 11.0, *) {\n                            Image(systemName: \"terminal\")\n                        }\n                        Text(URL(fileURLWithPath: path).lastPathComponent)\n                    }\n                    .tag(PickerSelection.value(selectedApp))\n                }\n            }\n\n            Text(\"Other App…\").tag(PickerSelection.other)\n            Text(\"Other Executable…\").tag(PickerSelection.otherExecutable)\n        }\n        .onAppear {\n            DispatchQueue.main.async {\n                state.refreshInstalledApps()\n            }\n        }\n    }\n}\n\nenum PickerSelection: Hashable {\n    case value(AppTarget?)\n    case other\n    case otherExecutable\n}\n\nstruct AppPickerItem: View {\n    var installedApp: InstalledApp\n\n    var body: some View {\n        HStack(spacing: 8) {\n            Image(nsImage: installedApp.bundleIcon)\n            Text(installedApp.bundleName)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/AppIndicator/AppPickerSheet/AppPickerSheet.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct AppPickerSheet: View {\n    @Binding var isPresented: Bool\n    @State private var selectedApp: AppTarget?\n    @State private var showDeleteAlert = false\n\n    @ObservedObject private var schemeState: SchemeState = .shared\n\n    private var shouldShowDeleteButton: Bool {\n        selectedApp != nil && schemeState.hasMatchingSchemes(\n            forApp: selectedApp,\n            forDisplay: schemeState.currentDisplay\n        )\n    }\n\n    var body: some View {\n        VStack(spacing: 18) {\n            Form {\n                AppPicker(selectedApp: $selectedApp)\n            }\n            .modifier(FormViewModifier())\n            .frame(minHeight: 96)\n\n            HStack(spacing: 8) {\n                if shouldShowDeleteButton {\n                    Button(\"Delete…\", action: onDelete)\n                        .sheetDestructiveActionStyle()\n                }\n                Spacer()\n                Button(\"Cancel\") {\n                    isPresented = false\n                }\n                .sheetSecondaryActionStyle()\n                .asCancelAction()\n                Button(\"OK\", action: onOK)\n                    .sheetPrimaryActionStyle()\n                    .asDefaultAction()\n            }\n            .padding(.horizontal, 18)\n            .padding(.bottom, 18)\n        }\n        .frame(minWidth: 372)\n        .onExitCommand {\n            isPresented = false\n        }\n        .onAppear {\n            selectedApp = schemeState.currentApp\n        }\n        .alert(isPresented: $showDeleteAlert) {\n            let appName = selectedApp.map { app in\n                switch app {\n                case let .bundle(bundleIdentifier):\n                    return (try? readInstalledApp(bundleIdentifier: bundleIdentifier)?.bundleName) ?? bundleIdentifier\n                case let .executable(path):\n                    return URL(fileURLWithPath: path).lastPathComponent\n                }\n            } ?? NSLocalizedString(\"All Apps\", comment: \"\")\n\n            return Alert(\n                title: Text(\"Delete Configuration?\"),\n                message: Text(\"This will delete all settings for \\\"\\(appName)\\\".\"),\n                primaryButton: .destructive(Text(\"Delete\")) {\n                    confirmDelete()\n                },\n                secondaryButton: .cancel()\n            )\n        }\n    }\n\n    @MainActor\n    private func onOK() {\n        isPresented = false\n        schemeState.currentApp = selectedApp\n    }\n\n    private func onDelete() {\n        showDeleteAlert = true\n    }\n\n    private func confirmDelete() {\n        schemeState.deleteMatchingSchemes(forApp: selectedApp, forDisplay: schemeState.currentDisplay)\n        isPresented = false\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/AppIndicator/AppPickerSheet/AppPickerState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Combine\nimport Foundation\n\nclass AppPickerState: ObservableObject {\n    static let shared: AppPickerState = .init()\n\n    private let schemeState: SchemeState = .shared\n    private let deviceState: DeviceState = .shared\n\n    @Published var installedApps: [InstalledApp] = []\n\n    private var runningAppSet: Set<String> {\n        Set(NSWorkspace.shared.runningApplications.map(\\.bundleIdentifier).compactMap(\\.self))\n    }\n\n    private var configuredAppSet: Set<String> {\n        guard let device = deviceState.currentDeviceRef?.value else {\n            return []\n        }\n\n        return Set(schemeState.schemes.allDeviceSpecficSchemes(of: device).reduce([String]()) { acc, element in\n            guard let app = element.element.if?.first?.app else {\n                return acc\n            }\n            return acc + [app]\n        })\n    }\n\n    private var configuredExecutableSet: Set<String> {\n        guard let device = deviceState.currentDeviceRef?.value else {\n            return []\n        }\n\n        return Set(schemeState.schemes.allDeviceSpecficSchemes(of: device).reduce([String]()) { acc, element in\n            guard let processPath = element.element.if?.first?.processPath else {\n                return acc\n            }\n            return acc + [processPath]\n        })\n    }\n\n    var configuredApps: [InstalledApp] {\n        configuredAppSet\n            .map {\n                try? readInstalledApp(bundleIdentifier: $0) ??\n                    .init(\n                        bundleName: $0,\n                        bundleIdentifier: $0,\n                        bundleIcon: NSWorkspace.shared.icon(forFile: \"\")\n                    )\n            }\n            .compactMap(\\.self)\n    }\n\n    var configuredExecutables: [String] {\n        Array(configuredExecutableSet).sorted()\n    }\n\n    var runningApps: [InstalledApp] {\n        let runningAppSet = runningAppSet\n        let configuredAppSet = configuredAppSet\n        return installedApps\n            .filter { runningAppSet.contains($0.bundleIdentifier) && !configuredAppSet.contains($0.bundleIdentifier) }\n    }\n\n    var otherApps: [InstalledApp] {\n        let runningAppSet = runningAppSet\n        let configuredAppSet = configuredAppSet\n        return installedApps\n            .filter { !runningAppSet.contains($0.bundleIdentifier) && !configuredAppSet.contains($0.bundleIdentifier) }\n    }\n}\n\nextension AppPickerState {\n    func refreshInstalledApps() {\n        installedApps = []\n\n        var seenBundleIdentifiers = Set<String>()\n\n        let fileManager = FileManager.default\n        for appDirURL in fileManager.urls(for: .applicationDirectory, in: .allDomainsMask) {\n            let appURLs = (try? fileManager\n                .contentsOfDirectory(at: appDirURL, includingPropertiesForKeys: nil)\n            ) ?? []\n            for appURL in appURLs {\n                guard let installedApp = try? readInstalledApp(at: appURL) else {\n                    continue\n                }\n                guard !seenBundleIdentifiers.contains(installedApp.bundleIdentifier) else {\n                    continue\n                }\n                installedApps.append(installedApp)\n                seenBundleIdentifiers.insert(installedApp.bundleIdentifier)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DeviceIndicator.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DeviceIndicator: View {\n    @ObservedObject private var state = DeviceIndicatorState.shared\n    @State private var showDevicePickerSheet = false\n\n    var body: some View {\n        Button {\n            showDevicePickerSheet.toggle()\n        } label: {\n            Text(state.activeDeviceName ?? \"Unknown\")\n                .frame(maxWidth: 190)\n                .fixedSize()\n                .lineLimit(1)\n        }\n        .controlSize(.small)\n        .buttonStyle(SecondaryButtonStyle())\n        .sheet(isPresented: $showDevicePickerSheet) {\n            DevicePickerSheet(isPresented: $showDevicePickerSheet)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DeviceIndicatorState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport SwiftUI\n\nclass DeviceIndicatorState: ObservableObject {\n    static let shared = DeviceIndicatorState()\n\n    @Published var activeDeviceName: String?\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    init() {\n        deviceState.$currentDeviceRef\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .removeDuplicates()\n            .sink { [weak self] _ in\n                self?.refreshActiveDeviceName()\n            }\n            .store(in: &subscriptions)\n\n        DeviceManager.shared\n            .$receiverPairedDeviceIdentities\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.refreshActiveDeviceName()\n            }\n            .store(in: &subscriptions)\n\n        DevicePickerState.shared\n            .objectWillChange\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.refreshActiveDeviceName()\n            }\n            .store(in: &subscriptions)\n    }\n}\n\nextension DeviceIndicatorState {\n    private var deviceState: DeviceState {\n        DeviceState.shared\n    }\n\n    private func refreshActiveDeviceName() {\n        guard let device = deviceState.currentDeviceRef?.value else {\n            activeDeviceName = nil\n            return\n        }\n\n        if let deviceModel = DevicePickerState.shared.devices.first(where: { $0.deviceRef.value === device }) {\n            activeDeviceName = deviceModel.displayName\n            return\n        }\n\n        activeDeviceName = DeviceManager.shared.displayName(for: device)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DeviceButtonStyle.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DeviceButtonStyle: ButtonStyle {\n    var isSelected: Bool\n\n    private var textColor: Color {\n        isSelected ? .accentColor : .primary\n    }\n\n    private var backgroundColor: Color {\n        backgroundColorPressed.opacity(0.2)\n    }\n\n    private var backgroundColorPressed: Color {\n        (isSelected ? Color.accentColor : .gray).opacity(0.2)\n    }\n\n    func makeBody(configuration: ButtonStyle.Configuration) -> some View {\n        configuration.label\n            .padding(.vertical, 2)\n            .padding(.horizontal, 12)\n            .foregroundColor(textColor)\n            .background(configuration.isPressed ? backgroundColorPressed : backgroundColor)\n            .cornerRadius(12)\n            .frame(maxWidth: .infinity, minHeight: 36)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DevicePicker.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DevicePicker: View {\n    @ObservedObject var state = DevicePickerState.shared\n\n    @Binding var selectedDeviceRef: WeakRef<Device>?\n    var onSelectDevice: (WeakRef<Device>) -> Void\n\n    var body: some View {\n        ScrollView {\n            VStack(alignment: .leading, spacing: 20) {\n                DevicePickerSection(\n                    selectedDeviceRef: $selectedDeviceRef, title: \"Mouse\",\n                    devices: state.devices.filter(\\.isMouse),\n                    onSelectDevice: onSelectDevice\n                )\n                DevicePickerSection(\n                    selectedDeviceRef: $selectedDeviceRef,\n                    title: \"Trackpad\",\n                    devices: state.devices.filter(\\.isTrackpad),\n                    onSelectDevice: onSelectDevice\n                )\n            }\n            .padding(.horizontal, 18)\n            .padding(.vertical, 6)\n        }\n        .frame(minWidth: 350)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DevicePickerBatteryCoordinator.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\nimport PointerKit\n\nfinal class DevicePickerBatteryCoordinator {\n    static let shared = DevicePickerBatteryCoordinator()\n\n    private let queue = DispatchQueue(label: \"linearmouse.device-picker-battery\", qos: .utility)\n    private var activeRefreshes = Set<Int32>()\n    private let lock = NSLock()\n\n    func refresh(_ deviceModel: DeviceModel) {\n        guard let device = deviceModel.deviceRef.value,\n              device.pointerDevice.vendorID == LogitechHIDPPDeviceMetadataProvider.Constants.vendorID,\n              device.pointerDevice.transport == PointerDeviceTransportName.bluetoothLowEnergy else {\n            return\n        }\n\n        let deviceID = device.id\n        lock.lock()\n        guard activeRefreshes.insert(deviceID).inserted else {\n            lock.unlock()\n            return\n        }\n        lock.unlock()\n\n        let pointerDevice = device.pointerDevice\n        queue.async { [weak self, weak deviceModel] in\n            let metadata = VendorSpecificDeviceMetadataRegistry.metadata(for: pointerDevice)\n            DispatchQueue.main.async {\n                deviceModel?.applyVendorSpecificMetadata(metadata)\n                self?.lock.lock()\n                self?.activeRefreshes.remove(deviceID)\n                self?.lock.unlock()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DevicePickerSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DevicePickerSection: View {\n    @Binding var selectedDeviceRef: WeakRef<Device>?\n\n    var title: LocalizedStringKey\n    var devices: [DeviceModel]\n    var onSelectDevice: (WeakRef<Device>) -> Void\n\n    var body: some View {\n        VStack(alignment: .leading, spacing: 10) {\n            Text(title)\n                .font(.body)\n                .foregroundColor(.secondary)\n\n            VStack(spacing: 8) {\n                ForEach(devices) { deviceModel in\n                    DevicePickerSectionItem(\n                        deviceModel: deviceModel,\n                        isSelected: isSelected(deviceModel)\n                    ) {\n                        selectedDeviceRef = deviceModel.deviceRef\n                        onSelectDevice(deviceModel.deviceRef)\n                    }\n                }\n            }\n        }\n        .frame(maxWidth: .infinity, alignment: .leading)\n    }\n\n    private func isSelected(_ deviceModel: DeviceModel) -> Bool {\n        guard let selectedDevice = selectedDeviceRef?.value else {\n            return false\n        }\n\n        return deviceModel.deviceRef.value === selectedDevice\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DevicePickerSectionItem.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DevicePickerSectionItem: View {\n    @ObservedObject var deviceModel: DeviceModel\n    var isSelected: Bool\n    var action: () -> Void\n\n    var body: some View {\n        Button(action: action) {\n            VStack(alignment: .leading, spacing: 6) {\n                HStack(spacing: 12) {\n                    HStack(alignment: .firstTextBaseline, spacing: 6) {\n                        Text(deviceModel.pairedReceiverDevices.isEmpty ? deviceModel.displayName : deviceModel.name)\n                            .font(.body)\n\n                        if let batteryLevel = deviceModel.batteryLevel,\n                           deviceModel.pairedReceiverDevices.isEmpty {\n                            BatteryLevelIndicator(level: batteryLevel)\n                        }\n\n                        if deviceModel.isActive {\n                            Text(\"(active)\")\n                                .font(.body)\n                                .foregroundColor(.secondary)\n                        }\n                    }\n                    .frame(maxWidth: .infinity, alignment: .leading)\n\n                    if isSelected, #available(macOS 11.0, *) {\n                        Image(systemName: \"checkmark\")\n                            .font(.system(size: 13, weight: .semibold))\n                            .foregroundColor(.accentColor)\n                            .accessibilityHidden(true)\n                    }\n                }\n\n                if !deviceModel.pairedReceiverDevices.isEmpty {\n                    VStack(alignment: .leading, spacing: 4) {\n                        ForEach(deviceModel.pairedReceiverDevices, id: \\.slot) { device in\n                            HStack(spacing: 6) {\n                                Text(String(format: NSLocalizedString(\"- %@\", comment: \"\"), device.name))\n                                    .font(.subheadline)\n                                    .foregroundColor(.secondary)\n\n                                if let batteryLevel = device.batteryLevel {\n                                    BatteryLevelIndicator(level: batteryLevel, compact: true)\n                                }\n                            }\n                        }\n                    }\n                    .padding(.leading, 12)\n                    .transition(\n                        .asymmetric(\n                            insertion: .opacity.combined(with: .move(edge: .top)),\n                            removal: .opacity.combined(with: .move(edge: .top))\n                        )\n                    )\n                }\n            }\n            .transition(\n                .asymmetric(\n                    insertion: .opacity.combined(with: .scale(scale: 0.97, anchor: .top)),\n                    removal: .opacity\n                )\n            )\n            .frame(\n                maxWidth: .infinity,\n                minHeight: deviceModel.pairedReceiverDevices.isEmpty ? 38 : 58,\n                alignment: .leading\n            )\n            .animation(\n                .spring(response: 0.26, dampingFraction: 0.88),\n                value: deviceModel.pairedReceiverDevices.map(\\.slot)\n            )\n        }\n        .buttonStyle(DeviceButtonStyle(isSelected: isSelected))\n    }\n}\n\nprivate struct BatteryLevelIndicator: View {\n    let level: Int\n    var compact = false\n\n    private var clampedLevel: Int {\n        min(max(level, 0), 100)\n    }\n\n    private var tintColor: Color {\n        switch clampedLevel {\n        case ..<16:\n            return .red\n        case ..<36:\n            return .orange\n        default:\n            return .green\n        }\n    }\n\n    private var bodyWidth: CGFloat {\n        compact ? 18 : 22\n    }\n\n    private var bodyHeight: CGFloat {\n        compact ? 9 : 11\n    }\n\n    private var fillWidth: CGFloat {\n        let usableWidth = bodyWidth - 4\n        let proportionalWidth = usableWidth * CGFloat(clampedLevel) / 100\n        return max(clampedLevel == 0 ? 0 : 2, proportionalWidth)\n    }\n\n    var body: some View {\n        HStack(spacing: compact ? 4 : 5) {\n            HStack(spacing: compact ? 3 : 4) {\n                ZStack(alignment: .leading) {\n                    RoundedRectangle(cornerRadius: bodyHeight / 3)\n                        .fill(Color.primary.opacity(0.05))\n\n                    RoundedRectangle(cornerRadius: bodyHeight / 3)\n                        .strokeBorder(Color.primary.opacity(0.22), lineWidth: 1)\n\n                    if fillWidth > 0 {\n                        RoundedRectangle(cornerRadius: (bodyHeight - 4) / 3)\n                            .fill(\n                                LinearGradient(\n                                    colors: [tintColor.opacity(0.95), tintColor.opacity(0.68)],\n                                    startPoint: .leading,\n                                    endPoint: .trailing\n                                )\n                            )\n                            .frame(width: fillWidth, height: bodyHeight - 4)\n                            .padding(2)\n                    }\n                }\n                .frame(width: bodyWidth, height: bodyHeight)\n\n                Capsule()\n                    .fill(Color.primary.opacity(0.18))\n                    .frame(width: compact ? 2 : 2.5, height: bodyHeight * 0.42)\n            }\n\n            Text(verbatim: formattedPercent(clampedLevel))\n                .font(compact ? .caption : .callout)\n                .foregroundColor(.secondary)\n                .font(.system(size: compact ? 11 : 12, weight: .regular, design: .monospaced))\n        }\n        .fixedSize()\n        .accessibilityElement(children: .ignore)\n        .accessibility(label: Text(\"Battery \\(formattedPercent(clampedLevel))\"))\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DevicePickerSheet.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\nimport SwiftUI\n\nstruct DevicePickerSheet: View {\n    @Binding var isPresented: Bool\n    @State private var autoSwitchToActiveDevice = Defaults[.autoSwitchToActiveDevice]\n    @State private var selectedDeviceRef: WeakRef<Device>?\n    @State private var showDeleteAlert = false\n\n    @ObservedObject private var schemeState: SchemeState = .shared\n    @ObservedObject private var deviceState: DeviceState = .shared\n\n    private var selectedDevice: Device? {\n        selectedDeviceRef?.value\n    }\n\n    private var shouldShowDeleteButton: Bool {\n        schemeState.hasMatchingSchemes(\n            for: selectedDevice,\n            forApp: schemeState.currentApp,\n            forDisplay: schemeState.currentDisplay\n        )\n    }\n\n    private var canConfirm: Bool {\n        autoSwitchToActiveDevice || selectedDeviceRef?.value != nil\n    }\n\n    private var autoSwitchBinding: Binding<Bool> {\n        Binding(\n            get: { autoSwitchToActiveDevice },\n            set: { newValue in\n                autoSwitchToActiveDevice = newValue\n                if newValue {\n                    syncSelectionWithCurrentDevice()\n                }\n            }\n        )\n    }\n\n    var body: some View {\n        VStack(spacing: 18) {\n            HStack(alignment: .top, spacing: 16) {\n                VStack(alignment: .leading, spacing: 4) {\n                    Text(\"Auto switch to the active device\")\n                    Text(\"Automatically follow the device that is currently active.\")\n                        .font(.subheadline)\n                        .foregroundColor(.secondary)\n                        .fixedSize(horizontal: false, vertical: true)\n                }\n                .frame(maxWidth: .infinity, alignment: .leading)\n\n                Toggle(String(\"\"), isOn: autoSwitchBinding.animation())\n                    .labelsHidden()\n                    .toggleStyle(.switch)\n                    .modifier(SheetToggleSizeModifier())\n            }\n            .padding(.horizontal, 18)\n            .padding(.top, 18)\n\n            DevicePicker(selectedDeviceRef: $selectedDeviceRef) { deviceRef in\n                handleDeviceSelection(deviceRef)\n            }\n            .frame(minHeight: 248, maxHeight: 320)\n\n            HStack(spacing: 8) {\n                if shouldShowDeleteButton {\n                    Button(\"Delete…\", action: onDelete)\n                        .sheetDestructiveActionStyle()\n                }\n\n                Spacer()\n\n                Button(\"Cancel\") {\n                    isPresented = false\n                }\n                .sheetSecondaryActionStyle()\n                .asCancelAction()\n\n                Button(\"OK\", action: onOK)\n                    .sheetPrimaryActionStyle()\n                    .asDefaultAction()\n                    .disabled(!canConfirm)\n            }\n            .padding(.horizontal, 18)\n            .padding(.bottom, 18)\n        }\n        .frame(minWidth: 372)\n        .onExitCommand {\n            isPresented = false\n        }\n        .onAppear {\n            autoSwitchToActiveDevice = Defaults[.autoSwitchToActiveDevice]\n            syncSelectionWithCurrentDevice()\n        }\n        .onReceive(deviceState.$currentDeviceRef.receive(on: RunLoop.main)) { currentDeviceRef in\n            if autoSwitchToActiveDevice {\n                selectedDeviceRef = currentDeviceRef\n            }\n        }\n        .alert(isPresented: $showDeleteAlert) {\n            Alert(\n                title: Text(\"Delete Configuration?\"),\n                message: Text(\"This will delete all settings for the selected device.\"),\n                primaryButton: .destructive(Text(\"Delete\")) {\n                    confirmDelete()\n                },\n                secondaryButton: .cancel()\n            )\n        }\n    }\n\n    private func onDelete() {\n        showDeleteAlert = true\n    }\n\n    private func handleDeviceSelection(_ deviceRef: WeakRef<Device>) {\n        selectedDeviceRef = deviceRef\n\n        let isSelectingActiveDevice = deviceRef.value === DeviceManager.shared.lastActiveDeviceRef?.value\n        if isSelectingActiveDevice {\n            autoSwitchToActiveDevice = true\n            syncSelectionWithCurrentDevice()\n        } else if autoSwitchToActiveDevice {\n            autoSwitchToActiveDevice = false\n        }\n    }\n\n    private func syncSelectionWithCurrentDevice() {\n        selectedDeviceRef = deviceState.currentDeviceRef\n    }\n\n    private func onOK() {\n        Defaults[.autoSwitchToActiveDevice] = autoSwitchToActiveDevice\n\n        if !autoSwitchToActiveDevice {\n            deviceState.currentDeviceRef = selectedDeviceRef\n        }\n\n        isPresented = false\n    }\n\n    private func confirmDelete() {\n        schemeState.deleteMatchingSchemes(\n            for: selectedDevice,\n            forApp: schemeState.currentApp,\n            forDisplay: schemeState.currentDisplay\n        )\n        isPresented = false\n    }\n}\n\nprivate struct SheetToggleSizeModifier: ViewModifier {\n    func body(content: Content) -> some View {\n        content.controlSize(.small)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DeviceIndicator/DevicePickerSheet/DevicePickerState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport SwiftUI\n\nclass DevicePickerState: ObservableObject {\n    static let shared = DevicePickerState()\n\n    var subscriptions = Set<AnyCancellable>()\n    private var cachedModels: [Device: DeviceModel] = [:]\n    private var modelSubscriptions: [Int32: AnyCancellable] = [:]\n\n    @Published var devices: [DeviceModel] = []\n\n    init() {\n        DeviceManager.shared\n            .$devices\n            .debounce(for: 0.1, scheduler: RunLoop.main)\n            .sink { [weak self] value in\n                self?.updateDevices(with: value)\n            }\n            .store(in: &subscriptions)\n    }\n\n    private func updateDevices(with devices: [Device]) {\n        let previousIDs = self.devices.map(\\.id)\n        let nextDevices = devices.map { device in\n            if let existingModel = cachedModels[device] {\n                DevicePickerBatteryCoordinator.shared.refresh(existingModel)\n                return existingModel\n            }\n\n            let model = DeviceModel(deviceRef: WeakRef(device))\n            cachedModels[device] = model\n            modelSubscriptions[model.id] = model.objectWillChange.sink { [weak self] _ in\n                self?.objectWillChange.send()\n            }\n            return model\n        }\n\n        cachedModels = cachedModels.filter { devices.contains($0.key) }\n        let validIDs = Set(nextDevices.map(\\.id))\n        modelSubscriptions = modelSubscriptions.filter { validIDs.contains($0.key) }\n        let nextIDs = nextDevices.map(\\.id)\n\n        guard previousIDs != nextIDs else {\n            self.devices = nextDevices\n            return\n        }\n\n        withAnimation(.spring(response: 0.24, dampingFraction: 0.9)) {\n            self.devices = nextDevices\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DisplayIndicator/DisplayIndicator.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DisplayIndicator: View {\n    @State private var showDisplayPickerSheet = false\n\n    @ObservedObject private var schemeState: SchemeState = .shared\n\n    var body: some View {\n        Button {\n            showDisplayPickerSheet.toggle()\n        } label: {\n            Text(schemeState.currentDisplay ?? NSLocalizedString(\"All Displays\", comment: \"\"))\n                .frame(maxWidth: 150)\n                .fixedSize()\n                .lineLimit(1)\n        }\n        .controlSize(.small)\n        .buttonStyle(SecondaryButtonStyle())\n        .sheet(isPresented: $showDisplayPickerSheet) {\n            DisplayPickerSheet(isPresented: $showDisplayPickerSheet)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DisplayIndicator/DisplayPickerSheet/DisplayPicker.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DisplayPicker: View {\n    @ObservedObject var state: DisplayPickerState = .shared\n    @Binding var selectedDisplay: String\n\n    var body: some View {\n        Picker(\"Configure for\", selection: $selectedDisplay) {\n            Text(\"All Displays\").frame(minHeight: 24).tag(\"\")\n            ForEach(state.allDisplays, id: \\.self) { display in\n                Text(display).tag(display)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DisplayIndicator/DisplayPickerSheet/DisplayPickerSheet.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct DisplayPickerSheet: View {\n    @Binding var isPresented: Bool\n    @State private var selectedDisplay = \"\"\n    @State private var showDeleteAlert = false\n\n    @ObservedObject private var schemeState: SchemeState = .shared\n\n    private var shouldShowDeleteButton: Bool {\n        // Only show if a display is selected and there are matching schemes\n        let display = selectedDisplay.isEmpty ? nil : selectedDisplay\n        return !selectedDisplay.isEmpty && schemeState.hasMatchingSchemes(\n            forApp: schemeState.currentApp,\n            forDisplay: display\n        )\n    }\n\n    var body: some View {\n        VStack(spacing: 18) {\n            Form {\n                DisplayPicker(selectedDisplay: $selectedDisplay)\n            }\n            .modifier(FormViewModifier())\n            .frame(minHeight: 96)\n\n            HStack(spacing: 8) {\n                if shouldShowDeleteButton {\n                    Button(\"Delete…\", action: onDelete)\n                        .sheetDestructiveActionStyle()\n                }\n                Spacer()\n                Button(\"Cancel\") {\n                    isPresented = false\n                }\n                .sheetSecondaryActionStyle()\n                .asCancelAction()\n                Button(\"OK\", action: onOK)\n                    .sheetPrimaryActionStyle()\n                    .asDefaultAction()\n            }\n            .padding(.horizontal, 18)\n            .padding(.bottom, 18)\n        }\n        .frame(minWidth: 372)\n        .onExitCommand {\n            isPresented = false\n        }\n        .onAppear {\n            selectedDisplay = schemeState.currentDisplay ?? \"\"\n        }\n        .alert(isPresented: $showDeleteAlert) {\n            let displayName = selectedDisplay.isEmpty ? NSLocalizedString(\"All Displays\", comment: \"\") : selectedDisplay\n\n            return Alert(\n                title: Text(\"Delete Configuration?\"),\n                message: Text(\"This will delete all settings for \\\"\\(displayName)\\\".\"),\n                primaryButton: .destructive(Text(\"Delete\")) {\n                    confirmDelete()\n                },\n                secondaryButton: .cancel()\n            )\n        }\n    }\n\n    private func onOK() {\n        isPresented = false\n        DispatchQueue.main.async {\n            schemeState.currentDisplay = selectedDisplay == \"\" ? nil : selectedDisplay\n        }\n    }\n\n    private func onDelete() {\n        showDeleteAlert = true\n    }\n\n    private func confirmDelete() {\n        let display = selectedDisplay.isEmpty ? nil : selectedDisplay\n        schemeState.deleteMatchingSchemes(forApp: schemeState.currentApp, forDisplay: display)\n        isPresented = false\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/DisplayIndicator/DisplayPickerSheet/DisplayPickerState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Combine\nimport Foundation\n\nclass DisplayPickerState: ObservableObject {\n    static let shared: DisplayPickerState = .init()\n\n    private let screenManager: ScreenManager = .shared\n\n    private let schemeState: SchemeState = .shared\n    private let deviceState: DeviceState = .shared\n\n    var allDisplays: [String] {\n        screenManager.screens.map(\\.nameOrLocalizedName)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Header/SchemeIndicator.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct SchemeIndicator: View {\n    var body: some View {\n        HStack {\n            DeviceIndicator()\n            AppIndicator()\n            DisplayIndicator()\n        }\n        .padding(.horizontal, 10)\n        .frame(height: 35, alignment: .leading)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/HelpButton/HelpButton.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct HelpButton: NSViewRepresentable {\n    let action: () -> Void\n\n    class Delegate: NSObject {\n        let callback: () -> Void\n\n        init(_ callback: @escaping () -> Void) {\n            self.callback = callback\n        }\n\n        @objc func action() {\n            callback()\n        }\n    }\n\n    func makeCoordinator() -> Delegate {\n        Delegate(action)\n    }\n\n    func makeNSView(context: NSViewRepresentableContext<Self>) -> NSButton {\n        let button = NSButton(title: \"\", target: context.coordinator, action: #selector(Delegate.action))\n        button.bezelStyle = .helpButton\n        return button\n    }\n\n    func updateNSView(_: NSButton, context _: NSViewRepresentableContext<Self>) {}\n}\n"
  },
  {
    "path": "LinearMouse/UI/HyperLink.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct HyperLink<Content: View>: View {\n    var url: URL\n    let content: () -> Content\n\n    init(\n        _ url: URL,\n        @ViewBuilder content: @escaping () -> Content\n    ) {\n        self.url = url\n        self.content = content\n    }\n\n    var body: some View {\n        Button {\n            NSWorkspace.shared.open(url)\n        } label: {\n            content()\n        }\n        .foregroundColor(.accentColor)\n        .buttonStyle(PlainButtonStyle())\n        .onHover { hovering in\n            if hovering {\n                NSCursor.pointingHand.push()\n            } else {\n                NSCursor.pop()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/PointerSettings/PointerSettings.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct PointerSettings: View {\n    @ObservedObject var state = PointerSettingsState.shared\n    @State private var isPointerSpeedLimitationPopoverPresented = false\n\n    var body: some View {\n        DetailView {\n            Form {\n                Section {\n                    HStack(spacing: 15) {\n                        Toggle(isOn: $state.pointerDisableAcceleration.animation()) {\n                            Text(\"Disable pointer acceleration\")\n                        }\n\n                        HelpButton {\n                            NSWorkspace.shared\n                                .open(URL(string: \"https://go.linearmouse.app/disable-pointer-acceleration-and-speed\")!)\n                        }\n                    }\n\n                    HStack(spacing: 15) {\n                        Toggle(isOn: $state.pointerRedirectsToScroll.animation()) {\n                            Text(\"Convert pointer movement to scroll events\")\n                            Text(\"Scrolling settings are applied to converted events.\")\n                                .controlSize(.small)\n                                .foregroundColor(.secondary)\n                        }\n                    }\n\n                    if !state.pointerDisableAcceleration {\n                        HStack(alignment: .firstTextBaseline) {\n                            Slider(\n                                value: $state.pointerAcceleration,\n                                in: 0.0 ... 20.0\n                            ) {\n                                labelWithDescription {\n                                    Text(\"Pointer acceleration\")\n                                    Text(verbatim: \"(0–20)\")\n                                }\n                            }\n                            TextField(\n                                String(\"\"),\n                                value: $state.pointerAcceleration,\n                                formatter: state.pointerAccelerationFormatter\n                            )\n                            .labelsHidden()\n                            .textFieldStyle(.roundedBorder)\n                            .multilineTextAlignment(.trailing)\n                            .frame(width: 80)\n                        }\n\n                        HStack(alignment: .firstTextBaseline) {\n                            Slider(\n                                value: $state.pointerSpeed,\n                                in: 0.0 ... 1.0\n                            ) {\n                                labelWithDescription {\n                                    HStack(spacing: 4) {\n                                        Text(\"Pointer speed\")\n\n                                        if state.showsPointerSpeedLimitationNotice {\n                                            Button {\n                                                isPointerSpeedLimitationPopoverPresented.toggle()\n                                            } label: {\n                                                Text(verbatim: \"⚠︎\")\n                                                    .foregroundColor(.orange)\n                                            }\n                                            .buttonStyle(PlainButtonStyle())\n                                            .popover(\n                                                isPresented: $isPointerSpeedLimitationPopoverPresented,\n                                                arrowEdge: .top\n                                            ) {\n                                                VStack(alignment: .leading, spacing: 10) {\n                                                    Text(\n                                                        \"Due to system limitations, this device may not support adjusting Pointer Speed on newer versions of macOS.\"\n                                                    )\n                                                    .fixedSize(horizontal: false, vertical: true)\n\n                                                    HyperLink(\n                                                        URL(\n                                                            string: \"https://go.linearmouse.app/pointer-speed-limitations\"\n                                                        )!\n                                                    ) {\n                                                        Text(\"Learn more\")\n                                                    }\n                                                }\n                                                .padding()\n                                                .frame(width: 280, alignment: .leading)\n                                            }\n                                        }\n                                    }\n\n                                    Text(verbatim: \"(0–1)\")\n                                }\n                            }\n                            TextField(\n                                String(\"\"),\n                                value: $state.pointerSpeed,\n                                formatter: state.pointerSpeedFormatter\n                            )\n                            .labelsHidden()\n                            .textFieldStyle(.roundedBorder)\n                            .multilineTextAlignment(.trailing)\n                            .frame(width: 80)\n                        }\n\n                        if #available(macOS 11.0, *) {\n                            Button(\"Revert to system defaults\") {\n                                revertPointerSpeed()\n                            }\n                            .keyboardShortcut(\"z\", modifiers: [.control, .command, .shift])\n\n                            Text(\"You may also press ⌃⇧⌘Z to revert to system defaults.\")\n                                .controlSize(.small)\n                                .foregroundColor(.secondary)\n                        } else {\n                            Button(\"Revert to system defaults\") {\n                                revertPointerSpeed()\n                            }\n                        }\n                    } else if #available(macOS 14, *) {\n                        HStack(alignment: .firstTextBaseline) {\n                            Slider(\n                                value: $state.pointerAcceleration,\n                                in: 0.0 ... 20.0\n                            ) {\n                                labelWithDescription {\n                                    Text(\"Tracking speed\")\n                                    Text(verbatim: \"(0–20)\")\n                                }\n                            }\n                            TextField(\n                                String(\"\"),\n                                value: $state.pointerAcceleration,\n                                formatter: state.pointerAccelerationFormatter\n                            )\n                            .labelsHidden()\n                            .textFieldStyle(.roundedBorder)\n                            .multilineTextAlignment(.trailing)\n                            .frame(width: 80)\n                        }\n\n                        Button(\"Revert to system defaults\") {\n                            revertPointerSpeed()\n                        }\n                        .keyboardShortcut(\"z\", modifiers: [.control, .command, .shift])\n\n                        Text(\"You may also press ⌃⇧⌘Z to revert to system defaults.\")\n                            .controlSize(.small)\n                            .foregroundColor(.secondary)\n                    }\n                }\n                .modifier(SectionViewModifier())\n            }\n            .modifier(FormViewModifier())\n        }\n    }\n\n    private func revertPointerSpeed() {\n        state.revertPointerSpeed()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/PointerSettings/PointerSettingsState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\nimport PublishedObject\n\nclass PointerSettingsState: ObservableObject {\n    static let shared: PointerSettingsState = .init()\n\n    @PublishedObject private var schemeState = SchemeState.shared\n    var scheme: Scheme {\n        get { schemeState.scheme }\n        set { schemeState.scheme = newValue }\n    }\n\n    var mergedScheme: Scheme {\n        schemeState.mergedScheme\n    }\n}\n\nextension PointerSettingsState {\n    var pointerDisableAcceleration: Bool {\n        get {\n            mergedScheme.pointer.disableAcceleration ?? false\n        }\n        set {\n            scheme.pointer.disableAcceleration = newValue\n        }\n    }\n\n    var pointerRedirectsToScroll: Bool {\n        get {\n            mergedScheme.pointer.redirectsToScroll ?? false\n        }\n        set {\n            scheme.pointer.redirectsToScroll = newValue\n            GlobalEventTap.shared.stop()\n            GlobalEventTap.shared.start()\n        }\n    }\n\n    var pointerAcceleration: Double {\n        get {\n            mergedScheme.pointer.acceleration?.unwrapped?.asTruncatedDouble\n                ?? mergedScheme.firstMatchedDevice?.pointerAcceleration\n                ?? Device.fallbackPointerAcceleration\n        }\n        set {\n            guard abs(pointerAcceleration - newValue) >= 0.0001 else {\n                return\n            }\n\n            scheme.pointer.acceleration = .value(Decimal(newValue).rounded(4))\n        }\n    }\n\n    var pointerSpeed: Double {\n        get {\n            mergedScheme.pointer.speed?.unwrapped?.asTruncatedDouble\n                ?? mergedScheme.firstMatchedDevice?.pointerSpeed\n                ?? Device.fallbackPointerSpeed\n        }\n        set {\n            guard abs(pointerSpeed - newValue) >= 0.0001 else {\n                return\n            }\n\n            scheme.pointer.speed = .value(Decimal(newValue).rounded(4))\n        }\n    }\n\n    var pointerAccelerationFormatter: NumberFormatter {\n        let formatter = NumberFormatter()\n        formatter.numberStyle = NumberFormatter.Style.decimal\n        formatter.roundingMode = NumberFormatter.RoundingMode.halfUp\n        formatter.maximumFractionDigits = 4\n        formatter.thousandSeparator = \"\"\n        return formatter\n    }\n\n    var pointerSpeedFormatter: NumberFormatter {\n        let formatter = NumberFormatter()\n        formatter.numberStyle = NumberFormatter.Style.decimal\n        formatter.roundingMode = NumberFormatter.RoundingMode.halfUp\n        formatter.maximumFractionDigits = 4\n        formatter.thousandSeparator = \"\"\n        return formatter\n    }\n\n    var showsPointerSpeedLimitationNotice: Bool {\n        mergedScheme.firstMatchedDevice?.showsPointerSpeedLimitationNotice ?? false\n    }\n\n    func revertPointerSpeed() {\n        let device = scheme.firstMatchedDevice\n\n        device?.restorePointerAccelerationAndPointerSpeed()\n\n        Scheme(\n            pointer: Scheme.Pointer(\n                acceleration: .unset,\n                speed: .unset,\n                disableAcceleration: false,\n                redirectsToScroll: false\n            )\n        )\n        .merge(into: &scheme)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/Header.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nextension ScrollingSettings {\n    struct Header: View {\n        var body: some View {\n            HStack {\n                Spacer()\n                DirectionPicker()\n                Spacer()\n            }\n            .padding(.top, 20)\n        }\n    }\n\n    struct DirectionPicker: View {\n        @ObservedObject var state = ScrollingSettingsState.shared\n\n        var body: some View {\n            Picker(String(\"\"), selection: $state.direction) {\n                ForEach(Scheme.Scrolling.BidirectionalDirection.allCases) { direction in\n                    Text(NSLocalizedString(direction.rawValue, comment: \"\")).tag(direction)\n                }\n            }\n            .pickerStyle(.segmented)\n            .fixedSize()\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ModifierKeysSection/ModifierAction+Binding.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport SwiftUI\n\nextension Binding where Value == Scheme.Scrolling.Modifiers.Action? {\n    var kind: Binding<Scheme.Scrolling.Modifiers.Action.Kind> {\n        Binding<Scheme.Scrolling.Modifiers.Action.Kind>(\n            get: {\n                wrappedValue?.kind ?? .defaultAction\n            },\n            set: {\n                wrappedValue = Scheme.Scrolling.Modifiers.Action(kind: $0)\n            }\n        )\n    }\n\n    var speedFactor: Binding<Double> {\n        Binding<Double>(\n            get: {\n                guard case let .changeSpeed(speedFactor) = wrappedValue else {\n                    return 1\n                }\n\n                return speedFactor.asTruncatedDouble\n            },\n            set: { value in\n                if value < 0 {\n                    wrappedValue = .changeSpeed(scale: Decimal(value).rounded(0))\n                } else if 0 ..< 0.1 ~= value {\n                    wrappedValue = .changeSpeed(scale: Decimal(value * 20).rounded(0) / 20)\n                } else if 0.1 ..< 1 ~= value {\n                    wrappedValue = .changeSpeed(scale: Decimal(value).rounded(1))\n                } else {\n                    wrappedValue = .changeSpeed(scale: Decimal(value * 2).rounded(0) / 2)\n                }\n            }\n        )\n    }\n}\n\nextension Scheme.Scrolling.Modifiers.Action.Kind {\n    @ViewBuilder\n    var label: some View {\n        switch self {\n        case .defaultAction:\n            Text(\"Default action\")\n        case .ignore:\n            Text(\"Ignore modifier\")\n        case .noAction:\n            Text(\"No action\")\n        case .alterOrientation:\n            Text(\"Alter orientation\")\n        case .changeSpeed:\n            Text(\"Change speed\")\n        case .zoom:\n            Text(\"Zoom\")\n        case .pinchZoom:\n            Text(\"Pinch zoom\")\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ModifierKeysSection/ModifierKeyActionPicker.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport SwiftUI\n\nextension ScrollingSettings.ModifierKeysSection {\n    struct ModifierKeyActionPicker: View {\n        var label: LocalizedStringKey\n        @Binding var action: Scheme.Scrolling.Modifiers.Action?\n\n        var body: some View {\n            Picker(label, selection: $action.kind) {\n                ForEach(ActionType.allCases) { type in\n                    type.label.tag(type)\n                    if type == .defaultAction || type == .noAction {\n                        Divider()\n                    }\n                }\n            }\n            .modifier(PickerViewModifier())\n\n            if case .some(.changeSpeed) = action {\n                HStack(spacing: 5) {\n                    Slider(\n                        value: $action.speedFactor,\n                        in: 0.05 ... 10.00\n                    )\n                    .labelsHidden()\n                    Text(verbatim: String(format: \"%0.2f ×\", $action.speedFactor.wrappedValue))\n                        .frame(width: 60, alignment: .trailing)\n                }\n            }\n        }\n    }\n}\n\nextension ScrollingSettings.ModifierKeysSection.ModifierKeyActionPicker {\n    typealias ActionType = Scheme.Scrolling.Modifiers.Action.Kind\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ModifierKeysSection/ModifierKeysSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nextension ScrollingSettings {\n    struct ModifierKeysSection: View {\n        @ObservedObject private var state = ScrollingSettingsState.shared\n\n        var body: some View {\n            Section(header: Text(\"Modifier Keys\")) {\n                ModifierKeyActionPicker(label: \"⌘ (Command)\", action: $state.modifiers.command)\n                ModifierKeyActionPicker(label: \"⇧ (Shift)\", action: $state.modifiers.shift)\n                ModifierKeyActionPicker(label: \"⌥ (Option)\", action: $state.modifiers.option)\n                ModifierKeyActionPicker(label: \"⌃ (Control)\", action: $state.modifiers.control)\n            }\n            .modifier(SectionViewModifier())\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ReverseScrollingSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nextension ScrollingSettings {\n    struct ReverseScrollingSection: View {\n        @ObservedObject private var state = ScrollingSettingsState.shared\n\n        var body: some View {\n            Section {\n                Toggle(isOn: $state.reverseScrolling) {\n                    withDescription {\n                        Text(\"Reverse scrolling\")\n                        if state.direction == .horizontal {\n                            Text(\"Some gestures, such as swiping back and forward, may stop working.\")\n                        }\n                    }\n                }\n            }\n            .modifier(SectionViewModifier())\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ScrollingModeSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nextension ScrollingSettings {\n    struct ScrollingModeSection: View {\n        @ObservedObject private var state = ScrollingSettingsState.shared\n\n        var body: some View {\n            Section {\n                Picker(\"Scrolling mode\", selection: $state.scrollingMode) {\n                    ForEach(ScrollingSettingsState.ScrollingMode.allCases) { scrollingMode in\n                        Text(scrollingMode.label).tag(scrollingMode)\n                    }\n                }\n                .modifier(PickerViewModifier())\n\n                switch state.scrollingMode {\n                case .accelerated:\n                    HStack(alignment: .firstTextBaseline) {\n                        Slider(\n                            value: $state.scrollingAcceleration,\n                            in: 0.0 ... 10.0\n                        ) {\n                            labelWithDescription {\n                                Text(\"Scrolling acceleration\")\n                                Text(verbatim: \"(0–10)\")\n                            }\n                        } minimumValueLabel: {\n                            Text(\"Linear\")\n                        } maximumValueLabel: {\n                            Text(\"Accelerated\")\n                        }\n                        TextField(\n                            String(\"\"),\n                            value: $state.scrollingAcceleration,\n                            formatter: state.scrollingAccelerationFormatter\n                        )\n                        .labelsHidden()\n                        .textFieldStyle(.roundedBorder)\n                        .multilineTextAlignment(.trailing)\n                        .frame(width: 60)\n                    }\n\n                    HStack(alignment: .firstTextBaseline) {\n                        Slider(\n                            value: $state.scrollingSpeed,\n                            in: 0.0 ... 128.0\n                        ) {\n                            labelWithDescription {\n                                Text(\"Scrolling speed\")\n                                Text(verbatim: \"(0–128)\")\n                            }\n                        } minimumValueLabel: {\n                            Text(\"Slow\")\n                        } maximumValueLabel: {\n                            Text(\"Fast\")\n                        }\n                        TextField(\n                            String(\"\"),\n                            value: $state.scrollingSpeed,\n                            formatter: state.scrollingSpeedFormatter\n                        )\n                        .labelsHidden()\n                        .textFieldStyle(.roundedBorder)\n                        .multilineTextAlignment(.trailing)\n                        .frame(width: 60)\n                    }\n\n                    if state.scrollingDisabled {\n                        Text(\"Scrolling is disabled based on the current settings.\")\n                            .controlSize(.small)\n                            .foregroundColor(.secondary)\n                            .fixedSize(horizontal: false, vertical: true)\n                    }\n\n                    HStack(spacing: 10) {\n                        Button(\"Revert to system defaults\") {\n                            state.scrollingMode = .accelerated\n                            state.scrollingAcceleration = 1\n                            state.scrollingSpeed = 0\n                        }\n\n                        if state.direction == .horizontal {\n                            Button(\"Copy settings from vertical\") {\n                                state.scheme.scrolling.distance.horizontal = state.mergedScheme.scrolling.distance\n                                    .vertical\n                                state.scheme.scrolling.acceleration.horizontal = state.mergedScheme.scrolling\n                                    .acceleration\n                                    .vertical\n                                state.scheme.scrolling.speed.horizontal = state.mergedScheme.scrolling.speed.vertical\n                            }\n                        }\n                    }\n\n                case .smoothed:\n                    ScrollingSettings.SmoothedScrollingSection()\n\n                case .byLines:\n                    Slider(\n                        value: $state.scrollingDistanceInLines,\n                        in: 0 ... 10,\n                        step: 1\n                    ) {\n                        Text(\"Distance\")\n                    } minimumValueLabel: {\n                        Text(verbatim: \"0\")\n                    } maximumValueLabel: {\n                        Text(verbatim: \"10\")\n                    }\n\n                case .byPixels:\n                    Slider(\n                        value: $state.scrollingDistanceInPixels,\n                        in: 0 ... 128\n                    ) {\n                        Text(\"Distance\")\n                    } minimumValueLabel: {\n                        Text(verbatim: \"0px\")\n                    } maximumValueLabel: {\n                        Text(verbatim: \"128px\")\n                    }\n                }\n            }\n            .modifier(SectionViewModifier())\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ScrollingSettings.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct ScrollingSettings: View {\n    var body: some View {\n        DetailView {\n            VStack(alignment: .leading) {\n                Header()\n\n                Form {\n                    ReverseScrollingSection()\n\n                    ScrollingModeSection()\n\n                    ModifierKeysSection()\n                }\n                .modifier(FormViewModifier())\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/ScrollingSettingsState.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Foundation\nimport PublishedObject\nimport SwiftUI\n\nclass ScrollingSettingsState: ObservableObject {\n    static let shared: ScrollingSettingsState = .init()\n\n    @PublishedObject private var schemeState = SchemeState.shared\n    private var smoothedCache = Scheme.Scrolling.Bidirectional<Scheme.Scrolling.Smoothed>()\n\n    var scheme: Scheme {\n        get { schemeState.scheme }\n        set { schemeState.scheme = newValue }\n    }\n\n    var mergedScheme: Scheme {\n        schemeState.mergedScheme\n    }\n\n    @Published var direction: Scheme.Scrolling.BidirectionalDirection = .vertical\n}\n\nextension ScrollingSettingsState {\n    var reverseScrolling: Bool {\n        get { mergedScheme.scrolling.reverse[direction] ?? false }\n        set { scheme.scrolling.reverse[direction] = newValue }\n    }\n\n    enum ScrollingMode: String, Identifiable, CaseIterable {\n        var id: Self {\n            self\n        }\n\n        case accelerated = \"Accelerated\"\n        case smoothed = \"Smoothed\"\n        case byLines = \"By Lines\"\n        case byPixels = \"By Pixels\"\n\n        var label: LocalizedStringKey {\n            switch self {\n            case .accelerated: \"Accelerated\"\n            case .smoothed: \"Smoothed (Beta)\"\n            case .byLines: \"By Lines\"\n            case .byPixels: \"By Pixels\"\n            }\n        }\n    }\n\n    var scrollingMode: ScrollingMode {\n        get {\n            if currentSmoothedConfiguration != nil {\n                return .smoothed\n            }\n\n            switch mergedScheme.scrolling.distance[direction] ?? .auto {\n            case .auto:\n                return .accelerated\n            case .line:\n                return .byLines\n            case .pixel:\n                return .byPixels\n            }\n        }\n        set {\n            switch newValue {\n            case .accelerated:\n                clearSmoothedConfiguration()\n                scheme.scrolling.distance[direction] = .auto\n                scheme.scrolling.acceleration[direction] = 1\n                scheme.scrolling.speed[direction] = 0\n            case .smoothed:\n                let smoothed = currentSmoothedConfiguration ?? makeDefaultSmoothedConfiguration()\n                setSmoothedConfiguration(smoothed)\n                scheme.scrolling.distance[direction] = .auto\n                scheme.scrolling.acceleration[direction] = 1\n                scheme.scrolling.speed[direction] = 0\n            case .byLines:\n                clearSmoothedConfiguration()\n                scheme.scrolling.distance[direction] = .line(3)\n                scheme.scrolling.acceleration[direction] = 1\n                scheme.scrolling.speed[direction] = 0\n            case .byPixels:\n                clearSmoothedConfiguration()\n                scheme.scrolling.distance[direction] = .pixel(36)\n                scheme.scrolling.acceleration[direction] = 1\n                scheme.scrolling.speed[direction] = 0\n            }\n        }\n    }\n\n    var scrollingAcceleration: Double {\n        get { mergedScheme.scrolling.acceleration[direction]?.asTruncatedDouble ?? 1 }\n        set { scheme.scrolling.acceleration[direction] = Decimal(newValue).rounded(2) }\n    }\n\n    var scrollingAccelerationFormatter: NumberFormatter {\n        decimalFormatter(maxFractionDigits: 2)\n    }\n\n    var scrollingSpeed: Double {\n        get { mergedScheme.scrolling.speed[direction]?.asTruncatedDouble ?? 0 }\n        set { scheme.scrolling.speed[direction] = Decimal(newValue).rounded(2) }\n    }\n\n    var scrollingSpeedFormatter: NumberFormatter {\n        decimalFormatter(maxFractionDigits: 2)\n    }\n\n    var scrollingDistanceInLines: Double {\n        get {\n            guard case let .line(lines) = mergedScheme.scrolling.distance[direction] else {\n                return 3\n            }\n            return Double(lines)\n        }\n        set {\n            scheme.scrolling.distance[direction] = .line(Int(newValue))\n        }\n    }\n\n    var scrollingDistanceInPixels: Double {\n        get {\n            guard case let .pixel(pixels) = mergedScheme.scrolling.distance[direction] else {\n                return 36\n            }\n            return pixels.asTruncatedDouble\n        }\n        set {\n            scheme.scrolling.distance[direction] = .pixel(Decimal(newValue).rounded(1))\n        }\n    }\n\n    var smoothedPreset: Scheme.Scrolling.Smoothed.Preset {\n        get { currentSmoothedConfiguration?.preset ?? .defaultPreset }\n        set {\n            selectSmoothedPreset(newValue)\n        }\n    }\n\n    var smoothedResponse: Double {\n        get { currentSmoothedConfiguration?.response?.asTruncatedDouble ?? 0.68 }\n        set {\n            updateSmoothedConfiguration {\n                $0.response = Decimal(newValue).rounded(2)\n            }\n        }\n    }\n\n    var smoothedResponseFormatter: NumberFormatter {\n        decimalFormatter(maxFractionDigits: 2)\n    }\n\n    var smoothedSpeed: Double {\n        get { currentSmoothedConfiguration?.speed?.asTruncatedDouble ?? 1.02 }\n        set {\n            updateSmoothedConfiguration {\n                $0.speed = Decimal(newValue).rounded(2)\n            }\n        }\n    }\n\n    var smoothedSpeedFormatter: NumberFormatter {\n        decimalFormatter(maxFractionDigits: 2)\n    }\n\n    var smoothedAcceleration: Double {\n        get { currentSmoothedConfiguration?.acceleration?.asTruncatedDouble ?? 1.10 }\n        set {\n            updateSmoothedConfiguration {\n                $0.acceleration = Decimal(newValue).rounded(2)\n            }\n        }\n    }\n\n    var smoothedAccelerationFormatter: NumberFormatter {\n        decimalFormatter(maxFractionDigits: 2)\n    }\n\n    var smoothedInertia: Double {\n        get { currentSmoothedConfiguration?.inertia?.asTruncatedDouble ?? 0.74 }\n        set {\n            updateSmoothedConfiguration {\n                $0.inertia = Decimal(newValue).rounded(2)\n            }\n        }\n    }\n\n    var smoothedInertiaFormatter: NumberFormatter {\n        decimalFormatter(maxFractionDigits: 2)\n    }\n\n    var scrollingDisabled: Bool {\n        switch scrollingMode {\n        case .accelerated:\n            return scrollingAcceleration == 0 && scrollingSpeed == 0\n        case .smoothed:\n            return smoothedResponse == 0 && smoothedSpeed == 0 && smoothedAcceleration == 0 && smoothedInertia == 0\n        case .byLines:\n            return scrollingDistanceInLines == 0\n        case .byPixels:\n            return scrollingDistanceInPixels == 0\n        }\n    }\n\n    var modifiers: Scheme.Scrolling.Modifiers {\n        get {\n            mergedScheme.scrolling.modifiers[direction] ?? .init()\n        }\n        set {\n            scheme.scrolling.modifiers[direction] = newValue\n        }\n    }\n\n    private var currentSmoothedConfiguration: Scheme.Scrolling.Smoothed? {\n        let configuration = scheme.scrolling.smoothed[direction]\n            ?? mergedScheme.scrolling.smoothed[direction]\n            ?? smoothedCache[direction]\n        guard configuration?.isEnabled == true else {\n            return nil\n        }\n        return configuration\n    }\n\n    func smoothedPreviewConfiguration(for preset: Scheme.Scrolling.Smoothed.Preset) -> Scheme.Scrolling.Smoothed {\n        if preset == .custom {\n            var configuration = scheme.scrolling.smoothed[direction]\n                ?? smoothedCache[direction]\n                ?? currentSmoothedConfiguration\n                ?? makeDefaultSmoothedConfiguration()\n            configuration.enabled = true\n            configuration.preset = .custom\n            return configuration\n        }\n\n        return preset.defaultConfiguration\n    }\n\n    func restoreDefaultSmoothedPreset() {\n        selectSmoothedPreset(.defaultPreset)\n    }\n\n    private func setSmoothedConfiguration(_ configuration: Scheme.Scrolling.Smoothed) {\n        var configuration = configuration\n        configuration.enabled = true\n        scheme.scrolling.smoothed[direction] = configuration\n        smoothedCache[direction] = configuration\n    }\n\n    private func clearSmoothedConfiguration() {\n        if let currentSmoothedConfiguration {\n            smoothedCache[direction] = currentSmoothedConfiguration\n        }\n\n        scheme.scrolling.smoothed[direction] = .init(enabled: false)\n    }\n\n    private func makeDefaultSmoothedConfiguration() -> Scheme.Scrolling.Smoothed {\n        Scheme.Scrolling.Smoothed.Preset.defaultPreset.defaultConfiguration\n    }\n\n    private func selectSmoothedPreset(_ preset: Scheme.Scrolling.Smoothed.Preset) {\n        if preset == .custom {\n            setSmoothedConfiguration(makeCustomSmoothedConfiguration())\n        } else {\n            setSmoothedConfiguration(preset.defaultConfiguration)\n        }\n    }\n\n    private func makeEditableSmoothedConfiguration() -> Scheme.Scrolling.Smoothed {\n        var configuration = currentSmoothedConfiguration\n            ?? scheme.scrolling.smoothed[direction]\n            ?? smoothedCache[direction]\n            ?? makeDefaultSmoothedConfiguration()\n        configuration.enabled = true\n        configuration.preset = configuration.preset ?? .defaultPreset\n        return configuration\n    }\n\n    private func makeCustomSmoothedConfiguration() -> Scheme.Scrolling.Smoothed {\n        var configuration = makeEditableSmoothedConfiguration()\n        configuration.preset = .custom\n        return configuration\n    }\n\n    private func updateSmoothedConfiguration(_ update: (inout Scheme.Scrolling.Smoothed) -> Void) {\n        var configuration = makeEditableSmoothedConfiguration()\n        update(&configuration)\n        setSmoothedConfiguration(configuration)\n    }\n\n    private func decimalFormatter(maxFractionDigits: Int) -> NumberFormatter {\n        let formatter = NumberFormatter()\n        formatter.numberStyle = .decimal\n        formatter.roundingMode = .halfUp\n        formatter.maximumFractionDigits = maxFractionDigits\n        formatter.thousandSeparator = \"\"\n        return formatter\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ScrollingSettings/SmoothedScrollingSection.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport SwiftUI\n\nextension ScrollingSettings {\n    struct SmoothedScrollingSection: View {\n        @ObservedObject private var state = ScrollingSettingsState.shared\n        @State private var isPresetPickerPresented = false\n\n        private var visiblePresets: [Scheme.Scrolling.Smoothed.Preset] {\n            let recommended = Scheme.Scrolling.Smoothed.Preset.recommendedCases\n            let current = state.smoothedPreset\n            return recommended.contains(current) ? recommended : [current] + recommended\n        }\n\n        var body: some View {\n            VStack(alignment: .leading, spacing: 14) {\n                withDescription {\n                    Text(\"Scrolling curve\")\n                    Text(\"Choose a feel preset.\")\n                }\n\n                presetPicker\n\n                sliderRow(\n                    title: \"Scroll response\",\n                    description: \"(0–2)\",\n                    value: Binding(\n                        get: { state.smoothedResponse },\n                        set: { state.smoothedResponse = $0 }\n                    ),\n                    range: Scheme.Scrolling.Smoothed.responseRange,\n                    minimumValueLabel: \"Loose\",\n                    maximumValueLabel: \"Immediate\",\n                    formatter: state.smoothedResponseFormatter\n                )\n\n                sliderRow(\n                    title: \"Scroll speed\",\n                    description: \"(0–8)\",\n                    value: Binding(\n                        get: { state.smoothedSpeed },\n                        set: { state.smoothedSpeed = $0 }\n                    ),\n                    range: Scheme.Scrolling.Smoothed.speedRange,\n                    minimumValueLabel: \"Slow\",\n                    maximumValueLabel: \"Fast\",\n                    formatter: state.smoothedSpeedFormatter\n                )\n\n                sliderRow(\n                    title: \"Scroll acceleration\",\n                    description: \"(0–8)\",\n                    value: Binding(\n                        get: { state.smoothedAcceleration },\n                        set: { state.smoothedAcceleration = $0 }\n                    ),\n                    range: Scheme.Scrolling.Smoothed.accelerationRange,\n                    minimumValueLabel: \"Flat\",\n                    maximumValueLabel: \"Adaptive\",\n                    formatter: state.smoothedAccelerationFormatter\n                )\n\n                sliderRow(\n                    title: \"Scroll inertia\",\n                    description: \"(0–8)\",\n                    value: Binding(\n                        get: { state.smoothedInertia },\n                        set: { state.smoothedInertia = $0 }\n                    ),\n                    range: Scheme.Scrolling.Smoothed.inertiaRange,\n                    minimumValueLabel: \"Short\",\n                    maximumValueLabel: \"Long\",\n                    formatter: state.smoothedInertiaFormatter\n                )\n\n                HStack(spacing: 10) {\n                    Button(\"Restore default preset\") {\n                        state.scrollingMode = .smoothed\n                        state.restoreDefaultSmoothedPreset()\n                    }\n\n                    if state.direction == .horizontal {\n                        Button(\"Copy settings from vertical\") {\n                            state.scheme.scrolling.smoothed.horizontal = state.mergedScheme.scrolling.smoothed.vertical\n                        }\n                    }\n                }\n            }\n        }\n\n        private var presetPicker: some View {\n            Button {\n                isPresetPickerPresented.toggle()\n            } label: {\n                HStack(spacing: 12) {\n                    SmoothedCurvePreview(\n                        configuration: state.smoothedPreviewConfiguration(for: state.smoothedPreset),\n                        highlighted: false,\n                        style: .compact\n                    )\n                    .frame(width: 92, height: 44)\n\n                    VStack(alignment: .leading, spacing: 2) {\n                        Text(state.smoothedPreset.presentation.title)\n                            .font(.headline)\n                            .foregroundColor(.primary)\n\n                        Text(state.smoothedPreset.presentation.subtitle)\n                            .font(.subheadline)\n                            .foregroundColor(.secondary)\n                            .lineLimit(1)\n                    }\n\n                    Spacer()\n\n                    Text(\"▾\")\n                        .font(.system(size: 12, weight: .semibold))\n                        .foregroundColor(.secondary)\n                }\n                .padding(.horizontal, 12)\n                .padding(.vertical, 10)\n                .background(\n                    RoundedRectangle(cornerRadius: 12, style: .continuous)\n                        .fill(Color(NSColor.controlBackgroundColor))\n                )\n                .overlay(\n                    RoundedRectangle(cornerRadius: 12, style: .continuous)\n                        .stroke(Color.secondary.opacity(0.18), lineWidth: 1)\n                )\n            }\n            .buttonStyle(.plain)\n            .popover(isPresented: $isPresetPickerPresented, arrowEdge: .top) {\n                ScrollView {\n                    VStack(alignment: .leading, spacing: 8) {\n                        ForEach(visiblePresets) { preset in\n                            presetMenuRow(for: preset)\n                        }\n                    }\n                    .padding(10)\n                }\n                .frame(width: 300, height: 400)\n            }\n        }\n\n        private func presetMenuRow(for preset: Scheme.Scrolling.Smoothed.Preset) -> some View {\n            let isSelected = state.smoothedPreset == preset\n            let configuration = state.smoothedPreviewConfiguration(for: preset)\n\n            return Button {\n                state.scrollingMode = .smoothed\n                state.smoothedPreset = preset\n                isPresetPickerPresented = false\n            } label: {\n                HStack(spacing: 12) {\n                    SmoothedCurvePreview(\n                        configuration: configuration,\n                        highlighted: isSelected,\n                        style: .compact\n                    )\n                    .frame(width: 92, height: 44)\n\n                    VStack(alignment: .leading, spacing: 3) {\n                        HStack(alignment: .firstTextBaseline, spacing: 6) {\n                            Text(preset.presentation.title)\n                                .font(.system(size: 13, weight: .semibold))\n                                .foregroundColor(.primary)\n                                .lineLimit(1)\n\n                            if preset.presentation.showsEditableBadge {\n                                Text(\"Editable\")\n                                    .font(.system(size: 10, weight: .medium))\n                                    .foregroundColor(.secondary)\n                            }\n                        }\n                    }\n\n                    Spacer(minLength: 0)\n\n                    if isSelected {\n                        Text(\"Selected\")\n                            .font(.system(size: 10, weight: .semibold))\n                            .foregroundColor(.accentColor)\n                    }\n                }\n                .padding(.horizontal, 10)\n                .padding(.vertical, 8)\n                .frame(maxWidth: .infinity, minHeight: 64, maxHeight: 64, alignment: .leading)\n                .background(\n                    RoundedRectangle(cornerRadius: 12, style: .continuous)\n                        .fill(isSelected ? Color.accentColor.opacity(0.12) : Color(NSColor.controlBackgroundColor))\n                )\n                .overlay(\n                    RoundedRectangle(cornerRadius: 12, style: .continuous)\n                        .stroke(\n                            isSelected ? Color.accentColor : Color.secondary.opacity(0.18),\n                            lineWidth: isSelected ? 1.5 : 1\n                        )\n                )\n            }\n            .buttonStyle(.plain)\n        }\n\n        private func sliderRow(\n            title: LocalizedStringKey,\n            description: String,\n            value: Binding<Double>,\n            range: ClosedRange<Double>,\n            minimumValueLabel: LocalizedStringKey,\n            maximumValueLabel: LocalizedStringKey,\n            formatter: NumberFormatter\n        ) -> some View {\n            HStack(alignment: .firstTextBaseline) {\n                Slider(\n                    value: value,\n                    in: range\n                ) {\n                    labelWithDescription {\n                        Text(title)\n                        Text(verbatim: description)\n                    }\n                } minimumValueLabel: {\n                    Text(minimumValueLabel)\n                } maximumValueLabel: {\n                    Text(maximumValueLabel)\n                }\n\n                DeferredNumberField(\n                    value: value,\n                    formatter: formatter,\n                    range: range\n                )\n                .frame(width: 60, height: 22)\n            }\n        }\n    }\n}\n\nprivate struct SmoothedCurvePreview: View {\n    enum Style {\n        case compact\n        case large\n    }\n\n    let configuration: Scheme.Scrolling.Smoothed\n    let highlighted: Bool\n    let style: Style\n\n    private var samples: [CGFloat] {\n        let count = style == .large ? 36 : 24\n        return (0 ..< count).map { index in\n            let t = CGFloat(index) / CGFloat(max(count - 1, 1))\n            return previewValue(at: t)\n        }\n    }\n\n    var body: some View {\n        GeometryReader { geometry in\n            let rect = geometry.frame(in: .local)\n\n            ZStack {\n                RoundedRectangle(cornerRadius: 10, style: .continuous)\n                    .fill(highlighted ? Color.accentColor.opacity(0.08) : Color(NSColor.windowBackgroundColor))\n\n                grid(in: rect)\n                    .stroke(Color.secondary.opacity(0.12), style: StrokeStyle(lineWidth: 1, dash: [3, 3]))\n\n                fillPath(in: rect)\n                    .fill(\n                        LinearGradient(\n                            colors: [\n                                Color.accentColor.opacity(highlighted ? 0.34 : 0.22),\n                                Color.accentColor.opacity(0.04)\n                            ],\n                            startPoint: .top,\n                            endPoint: .bottom\n                        )\n                    )\n\n                curvePath(in: rect)\n                    .stroke(\n                        highlighted ? Color.accentColor : Color.primary.opacity(0.72),\n                        style: StrokeStyle(lineWidth: highlighted ? 2.2 : 1.8, lineCap: .round, lineJoin: .round)\n                    )\n            }\n        }\n    }\n\n    private func grid(in rect: CGRect) -> Path {\n        var path = Path()\n\n        for step in 1 ..< 4 {\n            let y = rect.minY + (rect.height / 4) * CGFloat(step)\n            path.move(to: CGPoint(x: rect.minX + 8, y: y))\n            path.addLine(to: CGPoint(x: rect.maxX - 8, y: y))\n        }\n\n        return path\n    }\n\n    private func fillPath(in rect: CGRect) -> Path {\n        var path = curvePath(in: rect)\n        path.addLine(to: CGPoint(x: rect.maxX - 8, y: rect.maxY - 8))\n        path.addLine(to: CGPoint(x: rect.minX + 8, y: rect.maxY - 8))\n        path.closeSubpath()\n        return path\n    }\n\n    private func curvePath(in rect: CGRect) -> Path {\n        let insetRect = rect.insetBy(dx: 8, dy: 8)\n        let count = max(samples.count - 1, 1)\n\n        return Path { path in\n            for (index, sample) in samples.enumerated() {\n                let x = insetRect.minX + insetRect.width * CGFloat(index) / CGFloat(count)\n                let y = insetRect.maxY - insetRect.height * sample\n                let point = CGPoint(x: x, y: y)\n\n                if index == 0 {\n                    path.move(to: point)\n                } else {\n                    path.addLine(to: point)\n                }\n            }\n        }\n    }\n\n    private func previewValue(at t: CGFloat) -> CGFloat {\n        let preset = configuration.resolvedPreset\n\n        switch preset {\n        case .custom:\n            return dynamicPreviewValue(at: t)\n        case .linear:\n            return t\n        case .easeIn:\n            return pow(t, 2.2)\n        case .easeOut:\n            return 1 - pow(1 - t, 2.2)\n        case .easeInOut:\n            return easeInOutPower(t, power: 2.0)\n        case .quadratic:\n            return pow(t, 2.0)\n        case .cubic:\n            return pow(t, 3.0)\n        case .quartic:\n            return pow(t, 4.0)\n        case .easeOutCubic:\n            return 1 - pow(1 - t, 3.0)\n        case .easeInOutCubic:\n            return easeInOutPower(t, power: 3.0)\n        case .easeOutQuartic:\n            return 1 - pow(1 - t, 4.0)\n        case .easeInOutQuartic:\n            return easeInOutPower(t, power: 4.0)\n        case .smooth:\n            return easeInOutPower(t, power: 1.45)\n        }\n    }\n\n    private func dynamicPreviewValue(at t: CGFloat) -> CGFloat {\n        let response = CGFloat(configuration.response?.asTruncatedDouble ?? 0.68)\n        let speed = CGFloat(configuration.speed?.asTruncatedDouble ?? 1.0)\n        let acceleration = CGFloat(configuration.acceleration?.asTruncatedDouble ?? 1.0)\n        let inertia = CGFloat(configuration.inertia?.asTruncatedDouble ?? 0.8)\n\n        let leadingPower = max(0.8, 2.2 - response * 1.4 - speed * 0.15)\n        let tailPower = max(1.1, 1.2 + inertia * 0.7 + acceleration * 0.08)\n        let midpoint = min(max(0.35 + response * 0.18, 0.25), 0.75)\n\n        if t < midpoint {\n            let local = t / midpoint\n            return pow(local, leadingPower) * 0.52\n        }\n\n        let local = (t - midpoint) / max(1 - midpoint, 0.001)\n        return 0.52 + (1 - pow(1 - local, tailPower)) * 0.48\n    }\n\n    private func easeInOutPower(_ t: CGFloat, power: CGFloat) -> CGFloat {\n        if t < 0.5 {\n            return 0.5 * pow(t * 2, power)\n        }\n\n        return 1 - 0.5 * pow((1 - t) * 2, power)\n    }\n}\n\nprivate struct DeferredNumberField: NSViewRepresentable {\n    @Binding var value: Double\n    let formatter: NumberFormatter\n    let range: ClosedRange<Double>\n\n    init(value: Binding<Double>, formatter: NumberFormatter, range: ClosedRange<Double>) {\n        _value = value\n        self.formatter = formatter\n        self.range = range\n    }\n\n    func makeCoordinator() -> Coordinator {\n        Coordinator(parent: self)\n    }\n\n    func makeNSView(context: Context) -> NSTextField {\n        let textField = NSTextField(string: formattedValue(value))\n        textField.isBordered = true\n        textField.isBezeled = true\n        textField.bezelStyle = .roundedBezel\n        textField.focusRingType = .default\n        textField.alignment = .right\n        textField.delegate = context.coordinator\n        textField.usesSingleLineMode = true\n        textField.maximumNumberOfLines = 1\n        textField.lineBreakMode = .byClipping\n        return textField\n    }\n\n    func updateNSView(_ textField: NSTextField, context: Context) {\n        context.coordinator.parent = self\n\n        guard !context.coordinator.isEditing else {\n            return\n        }\n\n        let formatted = formattedValue(value)\n        if textField.stringValue != formatted {\n            textField.stringValue = formatted\n        }\n    }\n\n    private func formattedValue(_ value: Double) -> String {\n        formatter.string(from: NSNumber(value: value)) ?? \"\"\n    }\n\n    final class Coordinator: NSObject, NSTextFieldDelegate {\n        var parent: DeferredNumberField\n        var isEditing = false\n\n        init(parent: DeferredNumberField) {\n            self.parent = parent\n        }\n\n        func controlTextDidBeginEditing(_: Notification) {\n            isEditing = true\n        }\n\n        func controlTextDidEndEditing(_ notification: Notification) {\n            guard let textField = notification.object as? NSTextField else {\n                isEditing = false\n                return\n            }\n\n            commit(textField)\n            isEditing = false\n        }\n\n        func control(_ control: NSControl, textView _: NSTextView, doCommandBy commandSelector: Selector) -> Bool {\n            guard let textField = control as? NSTextField else {\n                return false\n            }\n\n            if commandSelector == #selector(NSResponder.insertNewline(_:)) {\n                commit(textField)\n                textField.window?.makeFirstResponder(nil)\n                return true\n            }\n\n            if commandSelector == #selector(NSResponder.cancelOperation(_:)) {\n                textField.stringValue = parent.formattedValue(parent.value)\n                textField.window?.makeFirstResponder(nil)\n                return true\n            }\n\n            return false\n        }\n\n        private func commit(_ textField: NSTextField) {\n            let trimmed = textField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)\n\n            guard !trimmed.isEmpty,\n                  let number = parent.formatter.number(from: trimmed) else {\n                textField.stringValue = parent.formattedValue(parent.value)\n                return\n            }\n\n            let clamped = min(max(number.doubleValue, parent.range.lowerBound), parent.range.upperBound)\n            parent.value = clamped\n            textField.stringValue = parent.formattedValue(clamped)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Settings.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Defaults\nimport SwiftUI\n\nstruct Settings: View {\n    @State private var showInDockTask: Task<Void, Never>?\n\n    var body: some View {\n        EmptyView()\n            .onAppear(perform: startShowInDockTask)\n            .onDisappear(perform: stopShowInDockTask)\n    }\n\n    private func startShowInDockTask() {\n        showInDockTask = Task {\n            for await value in Defaults.updates(.showInDock, initial: true) {\n                if value {\n                    NSApplication.shared.setActivationPolicy(.regular)\n                } else {\n                    NSApplication.shared.setActivationPolicy(.accessory)\n                    NSApplication.shared.activate(ignoringOtherApps: true)\n                }\n            }\n\n            NSApplication.shared.setActivationPolicy(.accessory)\n        }\n    }\n\n    private func stopShowInDockTask() {\n        showInDockTask?.cancel()\n        showInDockTask = nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/SettingsWindowController.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Cocoa\nimport Combine\nimport Defaults\nimport SwiftUI\n\nclass SettingsWindowController: NSWindowController {\n    static let shared = SettingsWindowController()\n\n    private var released = true\n    private var splitViewController: SettingsSplitViewController?\n    private var showInDockTask: Task<Void, Never>?\n\n    private func initWindowIfNeeded() {\n        guard released else {\n            return\n        }\n\n        let window = NSWindow(\n            contentRect: .init(x: 0, y: 0, width: 850, height: 600),\n            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],\n            backing: .buffered,\n            defer: false\n        )\n\n        window.delegate = self\n        window.title = LinearMouse.appName\n        window.minSize = NSSize(width: 850, height: 600)\n\n        if #available(macOS 26.0, *) {\n            // On macOS 26+, keep titlebar opaque to enable scroll edge effect (progressive blur)\n        } else {\n            window.titlebarAppearsTransparent = true\n        }\n\n        // Setup split view controller\n        let splitVC = SettingsSplitViewController()\n        splitViewController = splitVC\n        window.contentViewController = splitVC\n\n        // Setup toolbar with sidebar tracking separator\n        let toolbar = SettingsToolbar(splitViewController: splitVC)\n        window.toolbar = toolbar\n\n        if #available(macOS 11.0, *) {\n            window.toolbarStyle = .unified\n        }\n\n        window.center()\n\n        self.window = window\n        released = false\n\n        startShowInDockTask()\n    }\n\n    private func startShowInDockTask() {\n        showInDockTask = Task {\n            for await value in Defaults.updates(.showInDock, initial: true) {\n                if value {\n                    NSApplication.shared.setActivationPolicy(.regular)\n                } else {\n                    NSApplication.shared.setActivationPolicy(.accessory)\n                    NSApplication.shared.activate(ignoringOtherApps: true)\n                }\n            }\n\n            NSApplication.shared.setActivationPolicy(.accessory)\n        }\n    }\n\n    private func stopShowInDockTask() {\n        showInDockTask?.cancel()\n        showInDockTask = nil\n    }\n\n    func bringToFront() {\n        initWindowIfNeeded()\n\n        guard let window else {\n            return\n        }\n\n        window.bringToFront()\n    }\n}\n\nextension SettingsWindowController: NSWindowDelegate {\n    func windowWillClose(_: Notification) {\n        stopShowInDockTask()\n        splitViewController = nil\n        released = true\n    }\n}\n\n// MARK: - SettingsSplitViewController\n\nclass SettingsSplitViewController: NSSplitViewController {\n    private let sidebarViewController = SettingsSidebarViewController()\n    private let detailViewController = SettingsDetailViewController()\n\n    private var cancellables = Set<AnyCancellable>()\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        // Sidebar\n        let sidebarItem = NSSplitViewItem(sidebarWithViewController: sidebarViewController)\n        sidebarItem.canCollapse = false\n        sidebarItem.minimumThickness = 200\n        sidebarItem.maximumThickness = 250\n        if #available(macOS 11.0, *) {\n            sidebarItem.allowsFullHeightLayout = true\n        }\n        addSplitViewItem(sidebarItem)\n\n        // Detail\n        let detailItem = NSSplitViewItem(viewController: detailViewController)\n        detailItem.minimumThickness = 450\n        addSplitViewItem(detailItem)\n\n        // Observe navigation changes\n        SettingsState.shared\n            .$navigation\n            .receive(on: DispatchQueue.main)\n            .sink { [weak self] navigation in\n                self?.detailViewController.updateContent(for: navigation)\n            }\n            .store(in: &cancellables)\n    }\n\n    var currentNavigation: SettingsState.Navigation? {\n        SettingsState.shared.navigation\n    }\n}\n\n// MARK: - SettingsSidebarViewController\n\nclass SettingsSidebarViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {\n    private let tableView = NSTableView()\n    private let scrollView = NSScrollView()\n\n    private let items = SettingsState.Navigation.allCases\n\n    override func loadView() {\n        view = NSView()\n    }\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        setupTableView()\n        setupConstraints()\n\n        // Select initial row\n        if let navigation = SettingsState.shared.navigation,\n           let index = items.firstIndex(of: navigation) {\n            tableView.selectRowIndexes(IndexSet(integer: index), byExtendingSelection: false)\n        }\n    }\n\n    private func setupTableView() {\n        tableView.dataSource = self\n        tableView.delegate = self\n        tableView.headerView = nil\n        tableView.rowHeight = 32\n        if #available(macOS 11.0, *) {\n            tableView.style = .sourceList\n        }\n        tableView.selectionHighlightStyle = .sourceList\n\n        let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(\"SidebarColumn\"))\n        column.isEditable = false\n        tableView.addTableColumn(column)\n\n        scrollView.documentView = tableView\n        scrollView.hasVerticalScroller = true\n        scrollView.hasHorizontalScroller = false\n        scrollView.autohidesScrollers = true\n        scrollView.drawsBackground = false\n\n        view.addSubview(scrollView)\n    }\n\n    private func setupConstraints() {\n        scrollView.translatesAutoresizingMaskIntoConstraints = false\n        NSLayoutConstraint.activate([\n            scrollView.topAnchor.constraint(equalTo: view.topAnchor),\n            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),\n            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),\n            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)\n        ])\n    }\n\n    // MARK: - NSTableViewDataSource\n\n    func numberOfRows(in _: NSTableView) -> Int {\n        items.count\n    }\n\n    // MARK: - NSTableViewDelegate\n\n    func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {\n        let item = items[row]\n\n        let cellIdentifier = NSUserInterfaceItemIdentifier(\"SidebarCell\")\n        let cell: NSTableCellView\n\n        if let existingCell = tableView.makeView(withIdentifier: cellIdentifier, owner: nil) as? NSTableCellView {\n            cell = existingCell\n        } else {\n            cell = NSTableCellView()\n            cell.identifier = cellIdentifier\n\n            let imageView = NSImageView()\n            imageView.translatesAutoresizingMaskIntoConstraints = false\n            cell.addSubview(imageView)\n            cell.imageView = imageView\n\n            let textField = NSTextField(labelWithString: \"\")\n            textField.translatesAutoresizingMaskIntoConstraints = false\n            textField.lineBreakMode = .byTruncatingTail\n            cell.addSubview(textField)\n            cell.textField = textField\n\n            NSLayoutConstraint.activate([\n                imageView.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 4),\n                imageView.centerYAnchor.constraint(equalTo: cell.centerYAnchor),\n                imageView.widthAnchor.constraint(equalToConstant: 18),\n                imageView.heightAnchor.constraint(equalToConstant: 18),\n\n                textField.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 6),\n                textField.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -4),\n                textField.centerYAnchor.constraint(equalTo: cell.centerYAnchor)\n            ])\n        }\n\n        cell.imageView?.image = NSImage(named: item.imageName)\n        cell.textField?.stringValue = NSLocalizedString(item.rawValue.capitalized, comment: \"\")\n\n        return cell\n    }\n\n    func tableViewSelectionDidChange(_: Notification) {\n        let selectedRow = tableView.selectedRow\n        guard selectedRow >= 0, selectedRow < items.count else {\n            return\n        }\n        SettingsState.shared.navigation = items[selectedRow]\n    }\n}\n\n// MARK: - SettingsDetailViewController\n\nclass SettingsDetailViewController: NSViewController {\n    private var hostingController: NSHostingController<AnyView>?\n\n    override func loadView() {\n        view = NSView()\n        view.wantsLayer = true\n    }\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        updateContent(for: SettingsState.shared.navigation)\n    }\n\n    func updateContent(for navigation: SettingsState.Navigation?) {\n        // Remove old hosting controller\n        hostingController?.view.removeFromSuperview()\n        hostingController?.removeFromParent()\n\n        // Create new content\n        let content: AnyView\n        switch navigation {\n        case .pointer:\n            content = AnyView(PointerSettings())\n        case .scrolling:\n            content = AnyView(ScrollingSettings())\n        case .buttons:\n            content = AnyView(ButtonsSettings())\n        case .general:\n            content = AnyView(GeneralSettings())\n        case .none:\n            content = AnyView(\n                Text(\"Select an item from the sidebar\")\n                    .foregroundColor(.secondary)\n                    .frame(maxWidth: .infinity, maxHeight: .infinity)\n            )\n        }\n\n        let hosting = NSHostingController(rootView: content)\n        addChild(hosting)\n        view.addSubview(hosting.view)\n\n        hosting.view.translatesAutoresizingMaskIntoConstraints = false\n        NSLayoutConstraint.activate([\n            hosting.view.topAnchor.constraint(equalTo: view.topAnchor),\n            hosting.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),\n            hosting.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),\n            hosting.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)\n        ])\n\n        hostingController = hosting\n    }\n}\n\n// MARK: - SettingsToolbar\n\nclass SettingsToolbar: NSToolbar, NSToolbarDelegate {\n    private weak var splitViewController: SettingsSplitViewController?\n    private var cancellables = Set<AnyCancellable>()\n\n    private static let deviceItemIdentifier = NSToolbarItem.Identifier(\"device\")\n    private static let appItemIdentifier = NSToolbarItem.Identifier(\"app\")\n    private static let displayItemIdentifier = NSToolbarItem.Identifier(\"display\")\n    private static let flexibleSpaceIdentifier = NSToolbarItem.Identifier.flexibleSpace\n\n    init(splitViewController: SettingsSplitViewController) {\n        self.splitViewController = splitViewController\n        super.init(identifier: \"SettingsToolbar\")\n\n        delegate = self\n        displayMode = .iconOnly\n        allowsUserCustomization = false\n        if #available(macOS 15.0, *) {\n            allowsDisplayModeCustomization = false\n        }\n\n        // Observe navigation changes to show/hide toolbar items\n        SettingsState.shared\n            .$navigation\n            .receive(on: DispatchQueue.main)\n            .sink { [weak self] _ in\n                self?.validateVisibleItems()\n            }\n            .store(in: &cancellables)\n    }\n\n    private var shouldShowSchemeIndicators: Bool {\n        guard let navigation = splitViewController?.currentNavigation else {\n            return false\n        }\n        return navigation != .general\n    }\n\n    // MARK: - NSToolbarDelegate\n\n    func toolbar(\n        _: NSToolbar,\n        itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,\n        willBeInsertedIntoToolbar _: Bool\n    ) -> NSToolbarItem? {\n        switch itemIdentifier {\n        case Self.deviceItemIdentifier:\n            return createIndicatorItem(identifier: itemIdentifier, indicator: DeviceIndicatorButton())\n        case Self.appItemIdentifier:\n            return createIndicatorItem(identifier: itemIdentifier, indicator: AppIndicatorButton())\n        case Self.displayItemIdentifier:\n            return createIndicatorItem(identifier: itemIdentifier, indicator: DisplayIndicatorButton())\n        default:\n            return nil\n        }\n    }\n\n    func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {\n        var identifiers: [NSToolbarItem.Identifier] = []\n        if #available(macOS 11.0, *) {\n            identifiers.append(.sidebarTrackingSeparator)\n        }\n        identifiers.append(contentsOf: [\n            Self.flexibleSpaceIdentifier,\n            Self.deviceItemIdentifier,\n            Self.appItemIdentifier,\n            Self.displayItemIdentifier\n        ])\n        return identifiers\n    }\n\n    func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {\n        toolbarDefaultItemIdentifiers(toolbar)\n    }\n\n    private func createIndicatorItem(identifier: NSToolbarItem.Identifier, indicator: NSButton) -> NSToolbarItem {\n        let item = NSToolbarItem(itemIdentifier: identifier)\n        item.view = indicator\n        return item\n    }\n\n    func validateToolbarItem(_ item: NSToolbarItem) -> Bool {\n        switch item.itemIdentifier {\n        case Self.deviceItemIdentifier, Self.appItemIdentifier, Self.displayItemIdentifier:\n            item.view?.isHidden = !shouldShowSchemeIndicators\n            return shouldShowSchemeIndicators\n        default:\n            return true\n        }\n    }\n}\n\n// MARK: - Indicator Buttons\n\nclass DeviceIndicatorButton: NSButton {\n    private var cancellables = Set<AnyCancellable>()\n\n    init() {\n        super.init(frame: .zero)\n        setupButton()\n        bindState()\n    }\n\n    @available(*, unavailable)\n    required init?(coder _: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n\n    private func setupButton() {\n        bezelStyle = .toolbar\n        setButtonType(.momentaryPushIn)\n        target = self\n        action = #selector(showPicker)\n        translatesAutoresizingMaskIntoConstraints = false\n    }\n\n    private func bindState() {\n        title = DeviceIndicatorState.shared.activeDeviceName ?? NSLocalizedString(\"Unknown\", comment: \"\")\n        DeviceIndicatorState.shared\n            .$activeDeviceName\n            .receive(on: DispatchQueue.main)\n            .sink { [weak self] name in\n                self?.title = name ?? NSLocalizedString(\"Unknown\", comment: \"\")\n            }\n            .store(in: &cancellables)\n    }\n\n    @objc private func showPicker() {\n        guard let contentVC = window?.contentViewController else {\n            return\n        }\n        let sheetController = SheetController(content: DevicePickerSheetContent.self)\n        contentVC.presentAsSheet(sheetController)\n    }\n}\n\nclass AppIndicatorButton: NSButton {\n    private var cancellables = Set<AnyCancellable>()\n\n    init() {\n        super.init(frame: .zero)\n        setupButton()\n        bindState()\n    }\n\n    @available(*, unavailable)\n    required init?(coder _: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n\n    private func setupButton() {\n        bezelStyle = .toolbar\n        setButtonType(.momentaryPushIn)\n        target = self\n        action = #selector(showPicker)\n        translatesAutoresizingMaskIntoConstraints = false\n    }\n\n    private func bindState() {\n        title = SchemeState.shared.currentAppName ?? NSLocalizedString(\"All Apps\", comment: \"\")\n        SchemeState.shared\n            .$currentApp\n            .receive(on: DispatchQueue.main)\n            .sink { [weak self] _ in\n                let name = SchemeState.shared.currentAppName\n                self?.title = name ?? NSLocalizedString(\"All Apps\", comment: \"\")\n            }\n            .store(in: &cancellables)\n    }\n\n    @objc private func showPicker() {\n        guard let contentVC = window?.contentViewController else {\n            return\n        }\n        let sheetController = SheetController(content: AppPickerSheetContent.self)\n        contentVC.presentAsSheet(sheetController)\n    }\n}\n\nclass DisplayIndicatorButton: NSButton {\n    private var cancellables = Set<AnyCancellable>()\n\n    init() {\n        super.init(frame: .zero)\n        setupButton()\n        bindState()\n    }\n\n    @available(*, unavailable)\n    required init?(coder _: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n\n    private func setupButton() {\n        bezelStyle = .toolbar\n        setButtonType(.momentaryPushIn)\n        target = self\n        action = #selector(showPicker)\n        translatesAutoresizingMaskIntoConstraints = false\n    }\n\n    private func bindState() {\n        title = SchemeState.shared.currentDisplay ?? NSLocalizedString(\"All Displays\", comment: \"\")\n        SchemeState.shared\n            .$currentDisplay\n            .receive(on: DispatchQueue.main)\n            .sink { [weak self] name in\n                self?.title = name ?? NSLocalizedString(\"All Displays\", comment: \"\")\n            }\n            .store(in: &cancellables)\n    }\n\n    @objc private func showPicker() {\n        guard let contentVC = window?.contentViewController else {\n            return\n        }\n        let sheetController = SheetController(content: DisplayPickerSheetContent.self)\n        contentVC.presentAsSheet(sheetController)\n    }\n}\n\n// MARK: - Sheet Controller\n\nprivate protocol SheetContentView: View {\n    init(isPresented: Binding<Bool>)\n    static var preferredContentSize: NSSize? { get }\n}\n\nextension DevicePickerSheetContent: SheetContentView {}\nextension AppPickerSheetContent: SheetContentView {}\nextension DisplayPickerSheetContent: SheetContentView {}\n\nprivate class SheetController<Content: SheetContentView>: NSViewController {\n    private var hostingController: NSHostingController<Content>?\n    private var isPresented = true {\n        didSet {\n            if !isPresented {\n                dismiss(nil)\n            }\n        }\n    }\n\n    private let contentType: Content.Type\n\n    init(content: Content.Type) {\n        contentType = content\n        super.init(nibName: nil, bundle: nil)\n    }\n\n    @available(*, unavailable)\n    required init?(coder _: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n\n    override func loadView() {\n        view = NSView()\n    }\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        let binding = Binding<Bool>(\n            get: { [weak self] in self?.isPresented ?? false },\n            set: { [weak self] in self?.isPresented = $0 }\n        )\n\n        let content = contentType.init(isPresented: binding)\n        let hosting = NSHostingController(rootView: content)\n\n        addChild(hosting)\n        view.addSubview(hosting.view)\n\n        hosting.view.translatesAutoresizingMaskIntoConstraints = false\n        NSLayoutConstraint.activate([\n            hosting.view.topAnchor.constraint(equalTo: view.topAnchor),\n            hosting.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),\n            hosting.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),\n            hosting.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)\n        ])\n\n        hostingController = hosting\n\n        if let preferredContentSize = Content.preferredContentSize {\n            self.preferredContentSize = preferredContentSize\n        } else {\n            // Set preferred content size based on hosting view's fitting size\n            DispatchQueue.main.async { [weak self] in\n                guard let self, let hosting = self.hostingController else {\n                    return\n                }\n                let fittingSize = hosting.view.fittingSize\n                self.preferredContentSize = fittingSize\n            }\n        }\n    }\n\n    override func cancelOperation(_: Any?) {\n        isPresented = false\n    }\n}\n\n// MARK: - Sheet Content Views\n\nprivate struct DevicePickerSheetContent: View {\n    @Binding var isPresented: Bool\n\n    static let preferredContentSize: NSSize? = NSSize(width: 400, height: 410)\n\n    var body: some View {\n        DevicePickerSheet(isPresented: $isPresented)\n            .frame(width: 400, height: 410)\n    }\n}\n\nprivate struct AppPickerSheetContent: View {\n    @Binding var isPresented: Bool\n\n    static let preferredContentSize: NSSize? = nil\n\n    var body: some View {\n        AppPickerSheet(isPresented: $isPresented)\n            .frame(width: 400)\n    }\n}\n\nprivate struct DisplayPickerSheetContent: View {\n    @Binding var isPresented: Bool\n\n    static let preferredContentSize: NSSize? = nil\n\n    var body: some View {\n        DisplayPickerSheet(isPresented: $isPresented)\n            .frame(width: 400)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Sidebar/Sidebar.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct Sidebar: View {\n    @ObservedObject var state = SettingsState.shared\n\n    var body: some View {\n        List(SettingsState.Navigation.allCases, id: \\.self, selection: $state.navigation) { item in\n            SidebarRow(item: item)\n                .tag(item)\n        }\n        .listStyle(SidebarListStyle())\n    }\n}\n\nprivate struct SidebarRow: View {\n    let item: SettingsState.Navigation\n\n    var body: some View {\n        if #available(macOS 11.0, *) {\n            Label {\n                Text(item.title)\n            } icon: {\n                Image(item.imageName)\n                    .resizable()\n                    .aspectRatio(contentMode: .fit)\n                    .frame(width: 16, height: 16)\n            }\n        } else {\n            HStack {\n                Image(item.imageName)\n                    .resizable()\n                    .aspectRatio(contentMode: .fit)\n                    .frame(width: 16, height: 16)\n                Text(item.title)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/Sidebar/SidebarItem.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct SidebarItem: View {\n    @ObservedObject var settingsState = SettingsState.shared\n\n    var id: SettingsState.Navigation\n    var imageName: String?\n    var text: LocalizedStringKey\n\n    private var isActive: Bool {\n        settingsState.navigation == id\n    }\n\n    var body: some View {\n        Button {\n            DispatchQueue.main.async {\n                settingsState.navigation = id\n            }\n        } label: {\n            HStack {\n                if let imageName {\n                    Image(imageName)\n                        .resizable()\n                        .aspectRatio(contentMode: .fit)\n                        .frame(width: 14, height: 14)\n                        .foregroundColor(isActive ? .white : .accentColor)\n                    Text(text)\n                } else {\n                    Text(text)\n                }\n            }\n            .padding(.horizontal, 10)\n            .frame(maxWidth: .infinity, minHeight: 30, maxHeight: 30, alignment: .leading)\n            .contentShape(Rectangle())\n        }\n        .buttonStyle(.plain)\n        .background(Color.accentColor.opacity(isActive ? 1 : 0))\n        .cornerRadius(5)\n        .foregroundColor(isActive ? .white : .primary)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/StatusItem.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Combine\nimport Defaults\nimport LaunchAtLogin\nimport SwiftUI\n\nclass StatusItem: NSObject, NSMenuDelegate {\n    static let shared = StatusItem()\n\n    private lazy var statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    private lazy var menu: NSMenu = {\n        let menu = NSMenu()\n        menu.delegate = self\n\n        menu.items = baseMenuItems()\n\n        return menu\n    }()\n\n    private lazy var openSettingsItem: NSMenuItem = {\n        let item = NSMenuItem(\n            title: String(format: NSLocalizedString(\"%@ Settings…\", comment: \"\"), LinearMouse.appName),\n            action: #selector(openSettings),\n            keyEquivalent: \",\"\n        )\n        item.target = self\n        return item\n    }()\n\n    private lazy var configurationItem: NSMenuItem = {\n        let item = NSMenuItem(\n            title: NSLocalizedString(\"Config\", comment: \"\"),\n            action: nil,\n            keyEquivalent: \"\"\n        )\n        item.submenu = configurationMenu\n        return item\n    }()\n\n    private lazy var startAtLoginItem: NSMenuItem = {\n        let item = NSMenuItem(\n            title: String(format: NSLocalizedString(\"Start at login\", comment: \"\")),\n            action: #selector(toggleStartAtLogin),\n            keyEquivalent: \"\"\n        )\n        item.target = self\n        return item\n    }()\n\n    private lazy var openSettingsForFrontmostApplicationItem: NSMenuItem = {\n        let item = NSMenuItem(\n            title: \"\",\n            action: #selector(openSettingsForFrontmostApplication),\n            keyEquivalent: \"\"\n        )\n        item.target = self\n        return item\n    }()\n\n    private lazy var quitItem: NSMenuItem = {\n        let item = NSMenuItem(\n            title: String(format: NSLocalizedString(\"Quit %@\", comment: \"\"), LinearMouse.appName),\n            action: #selector(quit),\n            keyEquivalent: \"q\"\n        )\n        item.target = self\n        return item\n    }()\n\n    private lazy var configurationMenu: NSMenu = {\n        let configurationMenu = NSMenu()\n\n        let reloadItem = NSMenuItem(\n            title: NSLocalizedString(\"Reload\", comment: \"\"),\n            action: #selector(reloadConfiguration),\n            keyEquivalent: \"r\"\n        )\n\n        let revealInFinderItem = NSMenuItem(\n            title: NSLocalizedString(\"Reveal in Finder\", comment: \"\"),\n            action: #selector(revealConfigurationInFinder),\n            keyEquivalent: \"r\"\n        )\n        revealInFinderItem.keyEquivalentModifierMask = [.option, .command]\n\n        configurationMenu.items = [\n            reloadItem,\n            revealInFinderItem\n        ]\n\n        configurationMenu.items.forEach { $0.target = self }\n\n        return configurationMenu\n    }()\n\n    private var batteryItems = [NSMenuItem]()\n    private var batterySeparatorItem: NSMenuItem?\n    private var isMenuOpen = false\n\n    override init() {\n        super.init()\n\n        if let button = statusItem.button {\n            button.image = NSImage(named: \"MenuIcon\")\n            button.imagePosition = .imageOnly\n            button.action = #selector(statusItemAction(sender:))\n            button.target = self\n        }\n\n        updateStatusItemBatteryIndicator()\n\n        startAtLoginItem.state = LaunchAtLogin.isEnabled ? .on : .off\n        LaunchAtLogin.publisher\n            .receive(on: RunLoop.main)\n            .sink { [weak self] value in\n                self?.startAtLoginItem.state = value ? .on : .off\n            }\n            .store(in: &subscriptions)\n\n        updateOpenSettingsForFrontmostApplicationItem()\n        NSWorkspace.shared.notificationCenter.addObserver(\n            forName: NSWorkspace.didActivateApplicationNotification,\n            object: nil,\n            queue: .main\n        ) { [weak self] _ in\n            self?.updateOpenSettingsForFrontmostApplicationItem()\n        }\n\n        AccessibilityPermission.pollingUntilEnabled { [weak self] in\n            self?.setup()\n        }\n    }\n\n    private func rebuildMenuItems(includeBatteryItems: Bool) {\n        guard includeBatteryItems else {\n            removeBatteryItems()\n            return\n        }\n\n        let items = makeBatteryItems()\n        updateBatteryItems(items)\n    }\n\n    private func updateStatusItemBatteryIndicator() {\n        guard let button = statusItem.button else {\n            return\n        }\n\n        let batteryTitle = currentBatteryIndicatorTitle()\n        button.title = batteryTitle.map { \" \\($0)\" } ?? \"\"\n        button.imagePosition = batteryTitle == nil ? .imageOnly : .imageLeft\n    }\n\n    private func currentBatteryIndicatorTitle() -> String? {\n        Self.menuBarBatteryTitle(\n            currentBatteryLevel: currentDeviceBatteryLevel(),\n            mode: Defaults[.menuBarBatteryDisplayMode]\n        )\n    }\n\n    private func currentDeviceBatteryLevel() -> Int? {\n        guard let currentDevice = currentBatteryIndicatorDevice() else {\n            return nil\n        }\n\n        return BatteryDeviceMonitor.shared.currentDeviceBatteryLevel(for: currentDevice)\n    }\n\n    private func currentBatteryIndicatorDevice() -> Device? {\n        Self.menuBarBatteryDevice(\n            activeDeviceRef: DeviceManager.shared.lastActiveDeviceRef,\n            selectedDeviceRef: DeviceState.shared.currentDeviceRef\n        )\n    }\n\n    static func menuBarBatteryDevice<T: AnyObject>(activeDeviceRef: WeakRef<T>?, selectedDeviceRef: WeakRef<T>?) -> T? {\n        activeDeviceRef?.value ?? selectedDeviceRef?.value\n    }\n\n    static func menuBarBatteryTitle(currentBatteryLevel: Int?, mode: MenuBarBatteryDisplayMode) -> String? {\n        guard let threshold = mode.threshold,\n              let currentBatteryLevel\n        else {\n            return nil\n        }\n\n        guard currentBatteryLevel <= threshold else {\n            return nil\n        }\n\n        return formattedPercent(currentBatteryLevel)\n    }\n\n    private func baseMenuItems() -> [NSMenuItem] {\n        [\n            openSettingsItem,\n            .separator(),\n            configurationItem,\n            startAtLoginItem,\n            .separator(),\n            openSettingsForFrontmostApplicationItem,\n            quitItem\n        ]\n    }\n\n    private func makeBatteryItems() -> [NSMenuItem] {\n        BatteryDeviceMonitor.shared\n            .devices\n            .map { ($0.name, $0.batteryLevel) }\n            .sorted { lhs, rhs in\n                lhs.0.localizedCaseInsensitiveCompare(rhs.0) == .orderedAscending\n            }\n            .map { name, batteryLevel in\n                let item = NSMenuItem(\n                    title: \"\\(name) - \\(formattedPercent(batteryLevel))\",\n                    action: nil,\n                    keyEquivalent: \"\"\n                )\n                item.isEnabled = false\n                return item\n            }\n    }\n\n    private func updateBatteryItems(_ items: [NSMenuItem]) {\n        removeBatteryItems()\n\n        guard !items.isEmpty else {\n            return\n        }\n\n        let header = makeSectionHeader(title: NSLocalizedString(\"Batteries\", comment: \"\"))\n        let separator = NSMenuItem.separator()\n        menu.insertItem(separator, at: 0)\n        for item in items.reversed() {\n            menu.insertItem(item, at: 0)\n        }\n        menu.insertItem(header, at: 0)\n\n        batteryItems = [header] + items\n        batterySeparatorItem = separator\n    }\n\n    private func removeBatteryItems() {\n        for item in batteryItems {\n            menu.removeItem(item)\n        }\n        batteryItems.removeAll()\n\n        if let batterySeparatorItem {\n            menu.removeItem(batterySeparatorItem)\n            self.batterySeparatorItem = nil\n        }\n    }\n\n    private func makeSectionHeader(title: String) -> NSMenuItem {\n        let item = NSMenuItem(title: title, action: nil, keyEquivalent: \"\")\n        item.isEnabled = false\n        return item\n    }\n\n    private func updateOpenSettingsForFrontmostApplicationItem() {\n        guard let url = NSWorkspace.shared.frontmostApplication?.bundleURL,\n              let name = try? readInstalledApp(at: url)?.bundleName else {\n            openSettingsForFrontmostApplicationItem.isHidden = true\n            return\n        }\n        openSettingsForFrontmostApplicationItem.isHidden = false\n        openSettingsForFrontmostApplicationItem.title = String(\n            format: NSLocalizedString(\"Configure for %@…\", comment: \"\"),\n            name\n        )\n    }\n\n    private func setup() {\n        statusItem.menu = menu\n\n        BatteryDeviceMonitor.shared\n            .$devices\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                guard let self, self.statusItem.menu != nil else {\n                    return\n                }\n\n                self.updateStatusItemBatteryIndicator()\n\n                if self.isMenuOpen {\n                    self.rebuildMenuItems(includeBatteryItems: true)\n                }\n            }\n            .store(in: &subscriptions)\n\n        DeviceState.shared\n            .$currentDeviceRef\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.updateStatusItemBatteryIndicator()\n            }\n            .store(in: &subscriptions)\n\n        DeviceManager.shared\n            .$lastActiveDeviceRef\n            .receive(on: RunLoop.main)\n            .sink { [weak self] _ in\n                self?.updateStatusItemBatteryIndicator()\n            }\n            .store(in: &subscriptions)\n\n        Defaults.observe(.showInMenuBar) { [weak self] change in\n            guard let self else {\n                return\n            }\n\n            self.statusItem.isVisible = change.newValue\n            self.updateStatusItemBatteryIndicator()\n        }\n        .tieToLifetime(of: self)\n\n        Defaults.observe(.menuBarBatteryDisplayMode) { [weak self] _ in\n            self?.updateStatusItemBatteryIndicator()\n        }\n        .tieToLifetime(of: self)\n    }\n\n    func menuWillOpen(_: NSMenu) {\n        isMenuOpen = true\n        rebuildMenuItems(includeBatteryItems: true)\n    }\n\n    func menuDidClose(_: NSMenu) {\n        isMenuOpen = false\n        rebuildMenuItems(includeBatteryItems: false)\n    }\n\n    @objc private func statusItemAction(sender _: NSStatusBarButton) {\n        guard !AccessibilityPermission.enabled else {\n            return\n        }\n\n        AccessibilityPermissionWindow.shared.bringToFront()\n    }\n\n    @objc private func openSettings() {\n        SchemeState.shared.currentApp = nil\n        SchemeState.shared.currentDisplay = nil\n        SettingsWindowController.shared.bringToFront()\n    }\n\n    @objc private func openSettingsForFrontmostApplication() {\n        if let bundleIdentifier = NSWorkspace.shared.frontmostApplication?.bundleIdentifier {\n            SchemeState.shared.currentApp = .bundle(bundleIdentifier)\n        } else {\n            SchemeState.shared.currentApp = nil\n        }\n        SettingsWindowController.shared.bringToFront()\n    }\n\n    @objc private func reloadConfiguration() {\n        ConfigurationState.shared.reloadFromDisk()\n    }\n\n    @objc private func revealConfigurationInFinder() {\n        ConfigurationState.shared.revealInFinder()\n    }\n\n    @objc private func toggleStartAtLogin() {\n        LaunchAtLogin.isEnabled.toggle()\n    }\n\n    @objc private func quit() {\n        NSApplication.shared.terminate(nil)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/ViewModifiers/FormViewModifier.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct FormViewModifier: ViewModifier {\n    func body(content: Content) -> some View {\n        if #available(macOS 13.0, *) {\n            content\n                .formStyle(.grouped)\n        } else {\n            ScrollView {\n                content\n                    .padding(40)\n                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)\n            }\n        }\n    }\n}\n\nstruct SectionViewModifier: ViewModifier {\n    func body(content: Content) -> some View {\n        if #available(macOS 13.0, *) {\n            content\n        } else {\n            content\n\n            Spacer()\n                .frame(height: 30)\n        }\n    }\n}\n\nstruct PickerViewModifier: ViewModifier {\n    func body(content: Content) -> some View {\n        if #available(macOS 13.0, *) {\n            content\n        } else {\n            // TODO: fixedSize?\n            content\n        }\n    }\n}\n\nfunc withDescription<View1: View, View2: View>(@ViewBuilder content: () -> TupleView<(View1, View2)>) -> some View {\n    let c = content()\n\n    if #available(macOS 13.0, *) {\n        return Group {\n            c.value.0\n            c.value.1\n        }\n    } else {\n        return VStack(alignment: .leading) {\n            c.value.0\n            c.value\n                .1\n                .controlSize(.small)\n                .foregroundColor(.secondary)\n                .fixedSize(horizontal: false, vertical: true)\n        }\n    }\n}\n\nfunc labelWithDescription<\n    View1: View,\n    View2: View\n>(@ViewBuilder content: () -> TupleView<(View1, View2)>) -> some View {\n    let c = content()\n\n    if #available(macOS 13.0, *) {\n        return Group {\n            c.value.0\n            c.value.1\n        }\n    } else {\n        return VStack(alignment: .trailing) {\n            c.value.0\n            c.value\n                .1\n                .controlSize(.small)\n                .foregroundColor(.secondary)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/VisualEffectView.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport SwiftUI\n\nstruct VisualEffectView: NSViewRepresentable {\n    let material: NSVisualEffectView.Material\n    let blendingMode: NSVisualEffectView.BlendingMode\n\n    func makeNSView(context _: Context) -> NSVisualEffectView {\n        let visualEffectView = NSVisualEffectView()\n        visualEffectView.material = material\n        visualEffectView.blendingMode = blendingMode\n        visualEffectView.state = NSVisualEffectView.State.active\n        return visualEffectView\n    }\n\n    func updateNSView(_ visualEffectView: NSVisualEffectView, context _: Context) {\n        visualEffectView.material = material\n        visualEffectView.blendingMode = blendingMode\n    }\n}\n"
  },
  {
    "path": "LinearMouse/UI/zh-Hant-HK.lproj/Main.strings",
    "content": "/* Class = \"NSMenu\"; title = \"Find\"; ObjectID = \"1b7-l0-nxx\"; */\n\"1b7-l0-nxx.title\" = \"Find\";\n\n/* Class = \"NSMenuItem\"; title = \"Lower\"; ObjectID = \"1tx-W0-xDw\"; */\n\"1tx-W0-xDw.title\" = \"Lower\";\n\n/* Class = \"NSMenuItem\"; title = \"Customize Toolbar…\"; ObjectID = \"1UK-8n-QPP\"; */\n\"1UK-8n-QPP.title\" = \"Customize Toolbar…\";\n\n/* Class = \"NSMenuItem\"; title = \"LinearMouse\"; ObjectID = \"1Xt-HY-uBw\"; */\n\"1Xt-HY-uBw.title\" = \"LinearMouse\";\n\n/* Class = \"NSMenuItem\"; title = \"Raise\"; ObjectID = \"2h7-ER-AoG\"; */\n\"2h7-ER-AoG.title\" = \"Raise\";\n\n/* Class = \"NSMenuItem\"; title = \"Transformations\"; ObjectID = \"2oI-Rn-ZJC\"; */\n\"2oI-Rn-ZJC.title\" = \"Transformations\";\n\n/* Class = \"NSMenu\"; title = \"Spelling\"; ObjectID = \"3IN-sU-3Bg\"; */\n\"3IN-sU-3Bg.title\" = \"Spelling\";\n\n/* Class = \"NSMenuItem\"; title = \"Use Default\"; ObjectID = \"3Om-Ey-2VK\"; */\n\"3Om-Ey-2VK.title\" = \"Use Default\";\n\n/* Class = \"NSMenu\"; title = \"Speech\"; ObjectID = \"3rS-ZA-NoH\"; */\n\"3rS-ZA-NoH.title\" = \"Speech\";\n\n/* Class = \"NSMenuItem\"; title = \"Find\"; ObjectID = \"4EN-yA-p0u\"; */\n\"4EN-yA-p0u.title\" = \"Find\";\n\n/* Class = \"NSMenuItem\"; title = \"Enter Full Screen\"; ObjectID = \"4J7-dP-txa\"; */\n\"4J7-dP-txa.title\" = \"Enter Full Screen\";\n\n/* Class = \"NSMenuItem\"; title = \"Quit LinearMouse\"; ObjectID = \"4sb-4s-VLi\"; */\n\"4sb-4s-VLi.title\" = \"Quit LinearMouse\";\n\n/* Class = \"NSMenuItem\"; title = \"About LinearMouse\"; ObjectID = \"5kV-Vb-QxS\"; */\n\"5kV-Vb-QxS.title\" = \"About LinearMouse\";\n\n/* Class = \"NSMenuItem\"; title = \"Edit\"; ObjectID = \"5QF-Oa-p0T\"; */\n\"5QF-Oa-p0T.title\" = \"Edit\";\n\n/* Class = \"NSMenuItem\"; title = \"Copy Style\"; ObjectID = \"5Vv-lz-BsD\"; */\n\"5Vv-lz-BsD.title\" = \"Copy Style\";\n\n/* Class = \"NSMenuItem\"; title = \"Redo\"; ObjectID = \"6dh-zS-Vam\"; */\n\"6dh-zS-Vam.title\" = \"Redo\";\n\n/* Class = \"NSMenu\"; title = \"Writing Direction\"; ObjectID = \"8mr-sm-Yjd\"; */\n\"8mr-sm-Yjd.title\" = \"Writing Direction\";\n\n/* Class = \"NSMenuItem\"; title = \"Substitutions\"; ObjectID = \"9ic-FL-obx\"; */\n\"9ic-FL-obx.title\" = \"Substitutions\";\n\n/* Class = \"NSMenuItem\"; title = \"Smart Copy/Paste\"; ObjectID = \"9yt-4B-nSM\"; */\n\"9yt-4B-nSM.title\" = \"Smart Copy/Paste\";\n\n/* Class = \"NSMenuItem\"; title = \"Tighten\"; ObjectID = \"46P-cB-AYj\"; */\n\"46P-cB-AYj.title\" = \"Tighten\";\n\n/* Class = \"NSMenuItem\"; title = \"Correct Spelling Automatically\"; ObjectID = \"78Y-hA-62v\"; */\n\"78Y-hA-62v.title\" = \"Correct Spelling Automatically\";\n\n/* Class = \"NSMenuItem\"; title = \"Use Default\"; ObjectID = \"agt-UL-0e3\"; */\n\"agt-UL-0e3.title\" = \"Use Default\";\n\n/* Class = \"NSMenuItem\"; title = \"Print…\"; ObjectID = \"aTl-1u-JFS\"; */\n\"aTl-1u-JFS.title\" = \"Print…\";\n\n/* Class = \"NSMenuItem\"; title = \"Window\"; ObjectID = \"aUF-d1-5bR\"; */\n\"aUF-d1-5bR.title\" = \"Window\";\n\n/* Class = \"NSMenu\"; title = \"Font\"; ObjectID = \"aXa-aM-Jaq\"; */\n\"aXa-aM-Jaq.title\" = \"Font\";\n\n/* Class = \"NSMenu\"; title = \"Main Menu\"; ObjectID = \"AYu-sK-qS6\"; */\n\"AYu-sK-qS6.title\" = \"Main Menu\";\n\n/* Class = \"NSMenuItem\"; title = \"\\tLeft to Right\"; ObjectID = \"BgM-ve-c93\"; */\n\"BgM-ve-c93.title\" = \"\\tLeft to Right\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Colors\"; ObjectID = \"bgn-CT-cEk\"; */\n\"bgn-CT-cEk.title\" = \"Show Colors\";\n\n/* Class = \"NSMenu\"; title = \"File\"; ObjectID = \"bib-Uj-vzu\"; */\n\"bib-Uj-vzu.title\" = \"File\";\n\n/* Class = \"NSMenuItem\"; title = \"Preferences…\"; ObjectID = \"BOF-NM-1cW\"; */\n\"BOF-NM-1cW.title\" = \"Preferences…\";\n\n/* Class = \"NSMenuItem\"; title = \"Use Selection for Find\"; ObjectID = \"buJ-ug-pKt\"; */\n\"buJ-ug-pKt.title\" = \"Use Selection for Find\";\n\n/* Class = \"NSMenuItem\"; title = \"Save As…\"; ObjectID = \"Bw7-FT-i3A\"; */\n\"Bw7-FT-i3A.title\" = \"Save As…\";\n\n/* Class = \"NSMenu\"; title = \"Transformations\"; ObjectID = \"c8a-y6-VQd\"; */\n\"c8a-y6-VQd.title\" = \"Transformations\";\n\n/* Class = \"NSMenuItem\"; title = \"Use None\"; ObjectID = \"cDB-IK-hbR\"; */\n\"cDB-IK-hbR.title\" = \"Use None\";\n\n/* Class = \"NSMenuItem\"; title = \"Selection\"; ObjectID = \"cqv-fj-IhA\"; */\n\"cqv-fj-IhA.title\" = \"Selection\";\n\n/* Class = \"NSMenuItem\"; title = \"Smart Links\"; ObjectID = \"cwL-P1-jid\"; */\n\"cwL-P1-jid.title\" = \"Smart Links\";\n\n/* Class = \"NSMenu\"; title = \"Text\"; ObjectID = \"d9c-me-L2H\"; */\n\"d9c-me-L2H.title\" = \"Text\";\n\n/* Class = \"NSMenuItem\"; title = \"Make Lower Case\"; ObjectID = \"d9M-CD-aMd\"; */\n\"d9M-CD-aMd.title\" = \"Make Lower Case\";\n\n/* Class = \"NSMenuItem\"; title = \"File\"; ObjectID = \"dMs-cI-mzQ\"; */\n\"dMs-cI-mzQ.title\" = \"File\";\n\n/* Class = \"NSMenuItem\"; title = \"Undo\"; ObjectID = \"dRJ-4n-Yzg\"; */\n\"dRJ-4n-Yzg.title\" = \"Undo\";\n\n/* Class = \"NSMenuItem\"; title = \"Spelling and Grammar\"; ObjectID = \"Dv1-io-Yv7\"; */\n\"Dv1-io-Yv7.title\" = \"Spelling and Grammar\";\n\n/* Class = \"NSMenuItem\"; title = \"Close\"; ObjectID = \"DVo-aG-piG\"; */\n\"DVo-aG-piG.title\" = \"Close\";\n\n/* Class = \"NSMenu\"; title = \"Help\"; ObjectID = \"F2S-fz-NVQ\"; */\n\"F2S-fz-NVQ.title\" = \"Help\";\n\n/* Class = \"NSMenuItem\"; title = \"Text\"; ObjectID = \"Fal-I4-PZk\"; */\n\"Fal-I4-PZk.title\" = \"Text\";\n\n/* Class = \"NSMenu\"; title = \"Substitutions\"; ObjectID = \"FeM-D8-WVr\"; */\n\"FeM-D8-WVr.title\" = \"Substitutions\";\n\n/* Class = \"NSMenuItem\"; title = \"LinearMouse Help\"; ObjectID = \"FKE-Sm-Kum\"; */\n\"FKE-Sm-Kum.title\" = \"LinearMouse Help\";\n\n/* Class = \"NSMenuItem\"; title = \"Bold\"; ObjectID = \"GB9-OM-e27\"; */\n\"GB9-OM-e27.title\" = \"Bold\";\n\n/* Class = \"NSMenu\"; title = \"Format\"; ObjectID = \"GEO-Iw-cKr\"; */\n\"GEO-Iw-cKr.title\" = \"Format\";\n\n/* Class = \"NSMenuItem\"; title = \"Font\"; ObjectID = \"Gi5-1S-RQB\"; */\n\"Gi5-1S-RQB.title\" = \"Font\";\n\n/* Class = \"NSMenuItem\"; title = \"Use Default\"; ObjectID = \"GUa-eO-cwY\"; */\n\"GUa-eO-cwY.title\" = \"Use Default\";\n\n/* Class = \"NSMenuItem\"; title = \"Paste\"; ObjectID = \"gVA-U4-sdL\"; */\n\"gVA-U4-sdL.title\" = \"Paste\";\n\n/* Class = \"NSMenuItem\"; title = \"Writing Direction\"; ObjectID = \"H1b-Si-o9J\"; */\n\"H1b-Si-o9J.title\" = \"Writing Direction\";\n\n/* Class = \"NSMenuItem\"; title = \"View\"; ObjectID = \"H8h-7b-M4v\"; */\n\"H8h-7b-M4v.title\" = \"View\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Spelling and Grammar\"; ObjectID = \"HFo-cy-zxI\"; */\n\"HFo-cy-zxI.title\" = \"Show Spelling and Grammar\";\n\n/* Class = \"NSMenuItem\"; title = \"Text Replacement\"; ObjectID = \"HFQ-gK-NFA\"; */\n\"HFQ-gK-NFA.title\" = \"Text Replacement\";\n\n/* Class = \"NSMenuItem\"; title = \"Smart Quotes\"; ObjectID = \"hQb-2v-fYv\"; */\n\"hQb-2v-fYv.title\" = \"Smart Quotes\";\n\n/* Class = \"NSMenu\"; title = \"View\"; ObjectID = \"HyV-fh-RgO\"; */\n\"HyV-fh-RgO.title\" = \"View\";\n\n/* Class = \"NSMenuItem\"; title = \"Check Document Now\"; ObjectID = \"hz2-CU-CR7\"; */\n\"hz2-CU-CR7.title\" = \"Check Document Now\";\n\n/* Class = \"NSMenu\"; title = \"Services\"; ObjectID = \"hz9-B4-Xy5\"; */\n\"hz9-B4-Xy5.title\" = \"Services\";\n\n/* Class = \"NSMenuItem\"; title = \"Subscript\"; ObjectID = \"I0S-gh-46l\"; */\n\"I0S-gh-46l.title\" = \"Subscript\";\n\n/* Class = \"NSMenuItem\"; title = \"Smaller\"; ObjectID = \"i1d-Er-qST\"; */\n\"i1d-Er-qST.title\" = \"Smaller\";\n\n/* Class = \"NSMenuItem\"; title = \"Open…\"; ObjectID = \"IAo-SY-fd9\"; */\n\"IAo-SY-fd9.title\" = \"Open…\";\n\n/* Class = \"NSMenu\"; title = \"Baseline\"; ObjectID = \"ijk-EB-dga\"; */\n\"ijk-EB-dga.title\" = \"Baseline\";\n\n/* Class = \"NSMenuItem\"; title = \"Justify\"; ObjectID = \"J5U-5w-g23\"; */\n\"J5U-5w-g23.title\" = \"Justify\";\n\n/* Class = \"NSMenuItem\"; title = \"Use None\"; ObjectID = \"J7y-lM-qPV\"; */\n\"J7y-lM-qPV.title\" = \"Use None\";\n\n/* Class = \"NSMenuItem\"; title = \"Kern\"; ObjectID = \"jBQ-r6-VK2\"; */\n\"jBQ-r6-VK2.title\" = \"Kern\";\n\n/* Class = \"NSMenuItem\"; title = \"\\tRight to Left\"; ObjectID = \"jFq-tB-4Kx\"; */\n\"jFq-tB-4Kx.title\" = \"\\tRight to Left\";\n\n/* Class = \"NSMenuItem\"; title = \"Format\"; ObjectID = \"jxT-CU-nIS\"; */\n\"jxT-CU-nIS.title\" = \"Format\";\n\n/* Class = \"NSMenuItem\"; title = \"Revert to Saved\"; ObjectID = \"KaW-ft-85H\"; */\n\"KaW-ft-85H.title\" = \"Revert to Saved\";\n\n/* Class = \"NSMenuItem\"; title = \"Show All\"; ObjectID = \"Kd2-mp-pUS\"; */\n\"Kd2-mp-pUS.title\" = \"Show All\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Sidebar\"; ObjectID = \"kIP-vf-haE\"; */\n\"kIP-vf-haE.title\" = \"Show Sidebar\";\n\n/* Class = \"NSMenuItem\"; title = \"\\tLeft to Right\"; ObjectID = \"Lbh-J2-qVU\"; */\n\"Lbh-J2-qVU.title\" = \"\\tLeft to Right\";\n\n/* Class = \"NSMenuItem\"; title = \"Bring All to Front\"; ObjectID = \"LE2-aR-0XJ\"; */\n\"LE2-aR-0XJ.title\" = \"Bring All to Front\";\n\n/* Class = \"NSMenuItem\"; title = \"Paste Ruler\"; ObjectID = \"LVM-kO-fVI\"; */\n\"LVM-kO-fVI.title\" = \"Paste Ruler\";\n\n/* Class = \"NSMenuItem\"; title = \"Check Grammar With Spelling\"; ObjectID = \"mK6-2p-4JG\"; */\n\"mK6-2p-4JG.title\" = \"Check Grammar With Spelling\";\n\n/* Class = \"NSMenuItem\"; title = \"Copy Ruler\"; ObjectID = \"MkV-Pr-PK5\"; */\n\"MkV-Pr-PK5.title\" = \"Copy Ruler\";\n\n/* Class = \"NSMenuItem\"; title = \"Services\"; ObjectID = \"NMo-om-nkz\"; */\n\"NMo-om-nkz.title\" = \"Services\";\n\n/* Class = \"NSMenuItem\"; title = \"\\tDefault\"; ObjectID = \"Nop-cj-93Q\"; */\n\"Nop-cj-93Q.title\" = \"\\tDefault\";\n\n/* Class = \"NSMenuItem\"; title = \"Ligatures\"; ObjectID = \"o6e-r0-MWq\"; */\n\"o6e-r0-MWq.title\" = \"Ligatures\";\n\n/* Class = \"NSMenuItem\"; title = \"Baseline\"; ObjectID = \"OaQ-X3-Vso\"; */\n\"OaQ-X3-Vso.title\" = \"Baseline\";\n\n/* Class = \"NSMenu\"; title = \"Open Recent\"; ObjectID = \"oas-Oc-fiZ\"; */\n\"oas-Oc-fiZ.title\" = \"Open Recent\";\n\n/* Class = \"NSMenuItem\"; title = \"Loosen\"; ObjectID = \"ogc-rX-tC1\"; */\n\"ogc-rX-tC1.title\" = \"Loosen\";\n\n/* Class = \"NSMenuItem\"; title = \"Hide LinearMouse\"; ObjectID = \"Olw-nP-bQN\"; */\n\"Olw-nP-bQN.title\" = \"Hide LinearMouse\";\n\n/* Class = \"NSMenuItem\"; title = \"Find Previous\"; ObjectID = \"OwM-mh-QMV\"; */\n\"OwM-mh-QMV.title\" = \"Find Previous\";\n\n/* Class = \"NSMenuItem\"; title = \"Minimize\"; ObjectID = \"OY7-WF-poV\"; */\n\"OY7-WF-poV.title\" = \"Minimize\";\n\n/* Class = \"NSMenuItem\"; title = \"Stop Speaking\"; ObjectID = \"Oyz-dy-DGm\"; */\n\"Oyz-dy-DGm.title\" = \"Stop Speaking\";\n\n/* Class = \"NSMenuItem\"; title = \"Delete\"; ObjectID = \"pa3-QI-u2k\"; */\n\"pa3-QI-u2k.title\" = \"Delete\";\n\n/* Class = \"NSMenuItem\"; title = \"Bigger\"; ObjectID = \"Ptp-SP-VEL\"; */\n\"Ptp-SP-VEL.title\" = \"Bigger\";\n\n/* Class = \"NSMenuItem\"; title = \"Save…\"; ObjectID = \"pxx-59-PXV\"; */\n\"pxx-59-PXV.title\" = \"Save…\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Fonts\"; ObjectID = \"Q5e-8K-NDq\"; */\n\"Q5e-8K-NDq.title\" = \"Show Fonts\";\n\n/* Class = \"NSMenuItem\"; title = \"Find Next\"; ObjectID = \"q09-fT-Sye\"; */\n\"q09-fT-Sye.title\" = \"Find Next\";\n\n/* Class = \"NSMenuItem\"; title = \"Page Setup…\"; ObjectID = \"qIS-W8-SiK\"; */\n\"qIS-W8-SiK.title\" = \"Page Setup…\";\n\n/* Class = \"NSMenuItem\"; title = \"Zoom\"; ObjectID = \"R4o-n2-Eq4\"; */\n\"R4o-n2-Eq4.title\" = \"Zoom\";\n\n/* Class = \"NSMenuItem\"; title = \"\\tRight to Left\"; ObjectID = \"RB4-Sm-HuC\"; */\n\"RB4-Sm-HuC.title\" = \"\\tRight to Left\";\n\n/* Class = \"NSMenuItem\"; title = \"Check Spelling While Typing\"; ObjectID = \"rbD-Rh-wIN\"; */\n\"rbD-Rh-wIN.title\" = \"Check Spelling While Typing\";\n\n/* Class = \"NSMenuItem\"; title = \"Smart Dashes\"; ObjectID = \"rgM-f4-ycn\"; */\n\"rgM-f4-ycn.title\" = \"Smart Dashes\";\n\n/* Class = \"NSMenuItem\"; title = \"Superscript\"; ObjectID = \"Rqc-34-cIF\"; */\n\"Rqc-34-cIF.title\" = \"Superscript\";\n\n/* Class = \"NSMenuItem\"; title = \"Select All\"; ObjectID = \"Ruw-6m-B2m\"; */\n\"Ruw-6m-B2m.title\" = \"Select All\";\n\n/* Class = \"NSMenuItem\"; title = \"Jump to Selection\"; ObjectID = \"S0p-oC-mLd\"; */\n\"S0p-oC-mLd.title\" = \"Jump to Selection\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Toolbar\"; ObjectID = \"snW-S8-Cw5\"; */\n\"snW-S8-Cw5.title\" = \"Show Toolbar\";\n\n/* Class = \"NSMenu\"; title = \"Window\"; ObjectID = \"Td7-aD-5lo\"; */\n\"Td7-aD-5lo.title\" = \"Window\";\n\n/* Class = \"NSMenu\"; title = \"Kern\"; ObjectID = \"tlD-Oa-oAM\"; */\n\"tlD-Oa-oAM.title\" = \"Kern\";\n\n/* Class = \"NSMenuItem\"; title = \"Data Detectors\"; ObjectID = \"tRr-pd-1PS\"; */\n\"tRr-pd-1PS.title\" = \"Data Detectors\";\n\n/* Class = \"NSMenuItem\"; title = \"Open Recent\"; ObjectID = \"tXI-mr-wws\"; */\n\"tXI-mr-wws.title\" = \"Open Recent\";\n\n/* Class = \"NSMenuItem\"; title = \"Capitalize\"; ObjectID = \"UEZ-Bs-lqG\"; */\n\"UEZ-Bs-lqG.title\" = \"Capitalize\";\n\n/* Class = \"NSMenu\"; title = \"LinearMouse\"; ObjectID = \"uQy-DD-JDr\"; */\n\"uQy-DD-JDr.title\" = \"LinearMouse\";\n\n/* Class = \"NSMenuItem\"; title = \"Cut\"; ObjectID = \"uRl-iY-unG\"; */\n\"uRl-iY-unG.title\" = \"Cut\";\n\n/* Class = \"NSMenuItem\"; title = \"Hide Others\"; ObjectID = \"Vdr-fp-XzO\"; */\n\"Vdr-fp-XzO.title\" = \"Hide Others\";\n\n/* Class = \"NSMenuItem\"; title = \"Center\"; ObjectID = \"VIY-Ag-zcb\"; */\n\"VIY-Ag-zcb.title\" = \"Center\";\n\n/* Class = \"NSMenuItem\"; title = \"Italic\"; ObjectID = \"Vjx-xi-njq\"; */\n\"Vjx-xi-njq.title\" = \"Italic\";\n\n/* Class = \"NSMenuItem\"; title = \"Paste Style\"; ObjectID = \"vKC-jM-MkH\"; */\n\"vKC-jM-MkH.title\" = \"Paste Style\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Ruler\"; ObjectID = \"vLm-3I-IUL\"; */\n\"vLm-3I-IUL.title\" = \"Show Ruler\";\n\n/* Class = \"NSMenuItem\"; title = \"Make Upper Case\"; ObjectID = \"vmV-6d-7jI\"; */\n\"vmV-6d-7jI.title\" = \"Make Upper Case\";\n\n/* Class = \"NSMenuItem\"; title = \"Clear Menu\"; ObjectID = \"vNY-rz-j42\"; */\n\"vNY-rz-j42.title\" = \"Clear Menu\";\n\n/* Class = \"NSMenu\"; title = \"Ligatures\"; ObjectID = \"w0m-vy-SC9\"; */\n\"w0m-vy-SC9.title\" = \"Ligatures\";\n\n/* Class = \"NSMenu\"; title = \"Edit\"; ObjectID = \"W48-6f-4Dl\"; */\n\"W48-6f-4Dl.title\" = \"Edit\";\n\n/* Class = \"NSMenuItem\"; title = \"New\"; ObjectID = \"Was-JA-tGl\"; */\n\"Was-JA-tGl.title\" = \"New\";\n\n/* Class = \"NSMenuItem\"; title = \"Align Right\"; ObjectID = \"wb2-vD-lq4\"; */\n\"wb2-vD-lq4.title\" = \"Align Right\";\n\n/* Class = \"NSMenuItem\"; title = \"Paste and Match Style\"; ObjectID = \"WeT-3V-zwk\"; */\n\"WeT-3V-zwk.title\" = \"Paste and Match Style\";\n\n/* Class = \"NSMenuItem\"; title = \"Help\"; ObjectID = \"wpr-3q-Mcd\"; */\n\"wpr-3q-Mcd.title\" = \"Help\";\n\n/* Class = \"NSMenuItem\"; title = \"Underline\"; ObjectID = \"WRG-CD-K1S\"; */\n\"WRG-CD-K1S.title\" = \"Underline\";\n\n/* Class = \"NSMenuItem\"; title = \"Copy\"; ObjectID = \"x3v-GG-iWU\"; */\n\"x3v-GG-iWU.title\" = \"Copy\";\n\n/* Class = \"NSMenuItem\"; title = \"Use All\"; ObjectID = \"xQD-1f-W4t\"; */\n\"xQD-1f-W4t.title\" = \"Use All\";\n\n/* Class = \"NSMenuItem\"; title = \"Speech\"; ObjectID = \"xrE-MZ-jX0\"; */\n\"xrE-MZ-jX0.title\" = \"Speech\";\n\n/* Class = \"NSMenuItem\"; title = \"Find…\"; ObjectID = \"Xz5-n4-O0W\"; */\n\"Xz5-n4-O0W.title\" = \"Find…\";\n\n/* Class = \"NSMenuItem\"; title = \"Find and Replace…\"; ObjectID = \"YEy-JH-Tfz\"; */\n\"YEy-JH-Tfz.title\" = \"Find and Replace…\";\n\n/* Class = \"NSMenuItem\"; title = \"\\tDefault\"; ObjectID = \"YGs-j5-SAR\"; */\n\"YGs-j5-SAR.title\" = \"\\tDefault\";\n\n/* Class = \"NSMenuItem\"; title = \"Start Speaking\"; ObjectID = \"Ynk-f8-cLZ\"; */\n\"Ynk-f8-cLZ.title\" = \"Start Speaking\";\n\n/* Class = \"NSMenuItem\"; title = \"Show Substitutions\"; ObjectID = \"z6F-FW-3nz\"; */\n\"z6F-FW-3nz.title\" = \"Show Substitutions\";\n\n/* Class = \"NSMenuItem\"; title = \"Align Left\"; ObjectID = \"ZM1-6Q-yy1\"; */\n\"ZM1-6Q-yy1.title\" = \"Align Left\";\n\n/* Class = \"NSMenuItem\"; title = \"Paragraph\"; ObjectID = \"ZvO-Gk-QUH\"; */\n\"ZvO-Gk-QUH.title\" = \"Paragraph\";\n\n"
  },
  {
    "path": "LinearMouse/Utilities/Application.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\n\nenum Application {\n    static func restart() {\n        let url = URL(fileURLWithPath: Bundle.main.resourcePath!)\n        let path = url.deletingLastPathComponent().deletingLastPathComponent().absoluteString\n        let task = Process()\n        task.launchPath = \"/bin/sh\"\n        task.environment = [\"BUNDLE_PATH\": path]\n        task.arguments = [\n            \"-c\",\n            \"while $(kill -0 $PPID 2>/dev/null); do sleep .1; done; /usr/bin/open \\\"$BUNDLE_PATH\\\" --args --show\"\n        ]\n        do {\n            try task.run()\n        } catch {\n            NSAlert(error: error).runModal()\n        }\n        NSApplication.shared.terminate(nil)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/ApplicationBundle.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\n\nstruct InstalledApp: Identifiable {\n    var id: String {\n        bundleIdentifier\n    }\n\n    var bundleName: String\n    var bundleIdentifier: String\n    var bundleIcon: NSImage\n}\n\nfunc readInstalledApp(at url: URL) throws -> InstalledApp? {\n    guard let bundle = Bundle(url: url) else {\n        return nil\n    }\n    guard let bundleIdentifier = bundle.bundleIdentifier else {\n        return nil\n    }\n    let bundleName = bundle.object(forInfoDictionaryKey: \"CFBundleDisplayName\") as? String ??\n        bundle.object(forInfoDictionaryKey: kCFBundleNameKey as String) as? String ??\n        url.lastPathComponent\n    let bundleIcon = NSWorkspace.shared.icon(forFile: url.path)\n    bundleIcon.size.width = 16\n    bundleIcon.size.height = 16\n    return .init(bundleName: bundleName, bundleIdentifier: bundleIdentifier, bundleIcon: bundleIcon)\n}\n\nfunc readInstalledApp(bundleIdentifier: String) throws -> InstalledApp? {\n    guard let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleIdentifier) else {\n        return nil\n    }\n    return try readInstalledApp(at: url)\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/CGEvent+LinearMouseSynthetic.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport Foundation\n\nstruct LogitechControlIdentity: Codable, Equatable, Hashable {\n    static let kind = \"logitechControl\"\n\n    var controlID: Int\n    var productID: Int?\n    var serialNumber: String?\n}\n\nextension LogitechControlIdentity {\n    var specificityScore: Int {\n        if serialNumber != nil {\n            return 2\n        }\n\n        if productID != nil {\n            return 1\n        }\n\n        return 0\n    }\n\n    var userVisibleName: String {\n        String(format: \"Logitech Control 0x%04X\", controlID)\n    }\n\n    var controlIDValue: UInt16? {\n        UInt16(exactly: controlID)\n    }\n\n    func matches(_ other: LogitechControlIdentity) -> Bool {\n        guard controlID == other.controlID else {\n            return false\n        }\n\n        if let configuredSerialNumber = other.serialNumber {\n            guard let serialNumber else {\n                return false\n            }\n            return serialNumber.caseInsensitiveCompare(configuredSerialNumber) == .orderedSame\n        }\n\n        if let configuredProductID = other.productID {\n            guard let productID else {\n                return false\n            }\n            return productID == configuredProductID\n        }\n\n        return other.serialNumber == nil && other.productID == nil\n    }\n}\n\nextension LogitechControlIdentity {\n    private enum CodingKeys: String, CodingKey {\n        case kind\n        case controlID\n        case productID\n        case serialNumber\n        case logicalDeviceProductID\n        case logicalDeviceSerialNumber\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        controlID = try container.decode(Int.self, forKey: .controlID)\n        productID = try decodeProductID(in: container, keys: [.productID, .logicalDeviceProductID])\n        serialNumber = try container.decodeIfPresent(String.self, forKey: .serialNumber)\n            ?? container.decodeIfPresent(String.self, forKey: .logicalDeviceSerialNumber)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(Self.kind, forKey: .kind)\n        try container.encode(controlID, forKey: .controlID)\n        try container.encodeIfPresent(productID, forKey: .productID)\n        try container.encodeIfPresent(serialNumber, forKey: .serialNumber)\n    }\n\n    private func decodeProductID(\n        in container: KeyedDecodingContainer<CodingKeys>,\n        keys: [CodingKeys]\n    ) throws -> Int? {\n        for key in keys {\n            if let value = try? container.decode(Int.self, forKey: key) {\n                return value\n            }\n\n            if let hexValue = try? container.decode(String.self, forKey: key) {\n                let normalized = hexValue.hasPrefix(\"0x\") ? String(hexValue.dropFirst(2)) : hexValue\n                guard let parsed = Int(normalized, radix: 16) else {\n                    throw CustomDecodingError(in: container, error: ValueError.invalidProductID)\n                }\n                return parsed\n            }\n        }\n\n        return nil\n    }\n\n    private enum ValueError: LocalizedError {\n        case invalidProductID\n\n        var errorDescription: String? {\n            switch self {\n            case .invalidProductID:\n                return NSLocalizedString(\"Invalid Logitech productID\", comment: \"\")\n            }\n        }\n    }\n}\n\nextension CGEvent {\n    private static let linearMouseSyntheticEventUserData: Int64 = 0x534D_4F4F_5448\n    private static let gestureCleanupReleaseUserData: Int64 = 0x4745_5354_5552\n\n    var isLinearMouseSyntheticEvent: Bool {\n        get {\n            getIntegerValueField(.eventSourceUserData) == Self.linearMouseSyntheticEventUserData\n        }\n        set {\n            setIntegerValueField(\n                .eventSourceUserData,\n                value: newValue ? Self.linearMouseSyntheticEventUserData : 0\n            )\n        }\n    }\n\n    var isGestureCleanupRelease: Bool {\n        get {\n            getIntegerValueField(.eventSourceUserData) == Self.gestureCleanupReleaseUserData\n        }\n        set {\n            setIntegerValueField(\n                .eventSourceUserData,\n                value: newValue ? Self.gestureCleanupReleaseUserData : 0\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Codable/Clamp.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nprotocol ClampRange {\n    associatedtype Value: Codable\n    associatedtype RangeValue: Comparable\n\n    static var range: ClosedRange<RangeValue> { get }\n\n    /// Clamp a possibly-optional value to range; default provided below\n    static func clamp(_ value: Value?) -> Value?\n}\n\nextension ClampRange where Value: Comparable, Value == RangeValue {\n    static func clamp(_ value: Value?) -> Value? {\n        value.map { $0.clamped(to: range) }\n    }\n}\n\n@propertyWrapper\nstruct Clamp<T: ClampRange> {\n    private var value: T.Value?\n\n    var wrappedValue: T.Value? {\n        get { value }\n        set {\n            value = T.clamp(newValue)\n        }\n    }\n\n    init(wrappedValue value: T.Value?) {\n        wrappedValue = value\n    }\n}\n\nextension Clamp: Codable {\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n        wrappedValue = try container.decode(T.Value.self)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n        try container.encode(wrappedValue)\n    }\n}\n\nextension Clamp: Equatable where T.Value: Equatable {}\n\nextension KeyedDecodingContainer {\n    func decode<T: ClampRange>(\n        _ type: Clamp<T>.Type,\n        forKey key: Self.Key\n    ) throws -> Clamp<T> {\n        try decodeIfPresent(type, forKey: key) ?? Clamp<T>(wrappedValue: nil)\n    }\n}\n\nextension KeyedEncodingContainer {\n    mutating func encode<T: ClampRange>(\n        _ value: Clamp<T>,\n        forKey key: Self.Key\n    ) throws {\n        guard value.wrappedValue != nil else {\n            return\n        }\n\n        try encodeIfPresent(value, forKey: key)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Codable/HexRepresentation.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\n@propertyWrapper\nstruct HexRepresentation<Value: BinaryInteger & Codable>: Equatable, Hashable {\n    var wrappedValue: Value?\n\n    init(wrappedValue value: Value?) {\n        wrappedValue = value\n    }\n}\n\nextension HexRepresentation: CustomStringConvertible {\n    var description: String {\n        wrappedValue?.description ?? \"nil\"\n    }\n}\n\nextension HexRepresentation: Codable {\n    enum ValueError: Error {\n        case invalidValue\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n        do {\n            var hexValue = try container.decode(String.self)\n            if hexValue.hasPrefix(\"0x\") {\n                hexValue = String(hexValue.dropFirst(2))\n            }\n            guard let parsedValue = Int64(hexValue, radix: 16) else {\n                throw CustomDecodingError(in: container, error: ValueError.invalidValue)\n            }\n            wrappedValue = Value(parsedValue)\n        } catch {\n            wrappedValue = try container.decode(Value.self)\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n\n        guard let wrappedValue else {\n            try container.encodeNil()\n            return\n        }\n\n        try container.encode(\"0x\" + String(wrappedValue, radix: 16))\n    }\n}\n\nextension HexRepresentation.ValueError: LocalizedError {\n    var errorDescription: String? {\n        switch self {\n        case .invalidValue:\n            return NSLocalizedString(\"Invalid value\", comment: \"\")\n        }\n    }\n}\n\nextension KeyedDecodingContainer {\n    func decode<Value: BinaryInteger & Codable>(\n        _ type: HexRepresentation<Value>.Type,\n        forKey key: Self.Key\n    ) throws -> HexRepresentation<Value> {\n        try decodeIfPresent(type, forKey: key) ?? HexRepresentation(wrappedValue: nil)\n    }\n}\n\nextension KeyedEncodingContainer {\n    mutating func encode<Value: BinaryInteger & Codable>(\n        _ value: HexRepresentation<Value>,\n        forKey key: Self.Key\n    ) throws {\n        guard value.wrappedValue != nil else {\n            return\n        }\n\n        try encodeIfPresent(value, forKey: key)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Codable/ImplicitOptional.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nprotocol ImplicitInitable {\n    init()\n}\n\n@propertyWrapper\nstruct ImplicitOptional<WrappedValue: ImplicitInitable> {\n    var projectedValue: WrappedValue?\n\n    var wrappedValue: WrappedValue {\n        get { projectedValue ?? .init() }\n        set { projectedValue = newValue }\n    }\n\n    init() {}\n\n    init(wrappedValue: WrappedValue) {\n        self.wrappedValue = wrappedValue\n    }\n}\n\nextension ImplicitOptional: ExpressibleByNilLiteral {\n    init(nilLiteral _: ()) {}\n}\n\nextension ImplicitOptional: Equatable where WrappedValue: Equatable {}\n\nextension ImplicitOptional: Encodable where WrappedValue: Encodable {\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n        try container.encode(projectedValue)\n    }\n}\n\nextension ImplicitOptional: Decodable where WrappedValue: Decodable {\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n        projectedValue = try container.decode(WrappedValue?.self)\n    }\n}\n\nextension KeyedEncodingContainer {\n    mutating func encode<WrappedValue: Encodable & ImplicitInitable>(\n        _ value: ImplicitOptional<WrappedValue>,\n        forKey key: Self.Key\n    ) throws {\n        guard value.projectedValue != nil else {\n            return\n        }\n\n        // Call `encodeIfPresent` instead of `encode` to avoid infinite recursive.\n        // Probably not the best practice?\n        try encodeIfPresent(value.projectedValue, forKey: key)\n    }\n}\n\nextension KeyedDecodingContainer {\n    func decode<WrappedValue: Decodable & ImplicitInitable>(\n        _ type: ImplicitOptional<WrappedValue>.Type,\n        forKey key: Self.Key\n    ) throws -> ImplicitOptional<WrappedValue> {\n        try decodeIfPresent(type, forKey: key) ?? ImplicitOptional()\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Codable/SingleValueOrArray.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n// SwiftFormat will eat the empty lines between the file header and @propertyWrapper.\n// These comments should be removed when SwiftFormat fixes this bug.\n\n@propertyWrapper\nstruct SingleValueOrArray<Value: Codable> {\n    var wrappedValue: [Value]?\n\n    init(wrappedValue value: [Value]?) {\n        wrappedValue = value\n    }\n}\n\nextension SingleValueOrArray: CustomStringConvertible {\n    var description: String {\n        wrappedValue?.description ?? \"nil\"\n    }\n}\n\nextension SingleValueOrArray: Equatable where Value: Equatable {}\n\nextension SingleValueOrArray: Hashable where Value: Hashable {}\n\nextension SingleValueOrArray: Codable {\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n        do {\n            wrappedValue = try container.decode([Value].self)\n        } catch {\n            wrappedValue = try [container.decode(Value.self)]\n        }\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n        if let value = wrappedValue, value.count == 1 {\n            try container.encode(value[0])\n        } else {\n            try container.encode(wrappedValue)\n        }\n    }\n}\n\nextension KeyedDecodingContainer {\n    func decode<Value: Codable>(\n        _ type: SingleValueOrArray<Value>.Type,\n        forKey key: Self.Key\n    ) throws -> SingleValueOrArray<Value> {\n        try decodeIfPresent(type, forKey: key) ?? SingleValueOrArray(wrappedValue: nil)\n    }\n}\n\nextension KeyedEncodingContainer {\n    mutating func encode<Value: Codable>(_ value: SingleValueOrArray<Value>, forKey key: Self.Key) throws {\n        guard value.wrappedValue != nil else {\n            return\n        }\n\n        // Call `encodeIfPresent` instead of `encode` to avoid infinite recursive.\n        // Probably not the best practice?\n        try encodeIfPresent(value, forKey: key)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Codable/Unsettable.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nenum Unsettable<T: Codable & Equatable>: Equatable, Codable {\n    case value(T)\n    case unset\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n\n        // Try decoding the sentinel string \"unset\"\n        if let string = try? container.decode(String.self), string == \"unset\" {\n            self = .unset\n            return\n        }\n\n        // Otherwise, decode the underlying value\n        let value = try container.decode(T.self)\n        self = .value(value)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n        switch self {\n        case let .value(value):\n            try container.encode(value)\n        case .unset:\n            try container.encode(\"unset\")\n        }\n    }\n}\n\nextension Unsettable {\n    var unwrapped: T? {\n        if case let .value(value) = self {\n            return value\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/CustomDecodingError.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nstruct CustomDecodingError: Error {\n    var codingPath: [CodingKey]\n    var error: Error\n}\n\nextension CustomDecodingError {\n    init(in container: SingleValueDecodingContainer, error: Error) {\n        codingPath = container.codingPath\n        self.error = error\n    }\n\n    init(in container: UnkeyedDecodingContainer, error: Error) {\n        codingPath = container.codingPath\n        self.error = error\n    }\n\n    init<K>(in container: KeyedDecodingContainer<K>, error: Error) {\n        codingPath = container.codingPath\n        self.error = error\n    }\n}\n\nextension CustomDecodingError: CustomStringConvertible {\n    var description: String {\n        String(describing: error)\n    }\n}\n\nextension CustomDecodingError: LocalizedError {\n    var errorDescription: String? {\n        String(\n            format: NSLocalizedString(\"%1$@ (%2$@)\", comment: \"\"),\n            error.localizedDescription,\n            codingPath.map(\\.stringValue).joined(separator: \".\")\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\nimport LRUCache\nimport SwiftUI\n\nprivate let wholePercentNumberFormatter: NumberFormatter = {\n    let formatter = NumberFormatter()\n    formatter.numberStyle = .percent\n    formatter.maximumFractionDigits = 0\n    formatter.minimumFractionDigits = 0\n    return formatter\n}()\n\nextension Comparable {\n    func clamped(to range: ClosedRange<Self>) -> Self {\n        min(max(range.lowerBound, self), range.upperBound)\n    }\n}\n\nextension BinaryInteger {\n    func normalized(\n        fromLowerBound: Self = 0,\n        fromUpperBound: Self = 1,\n        toLowerBound: Self = 0,\n        toUpperBound: Self = 1\n    ) -> Self {\n        let k = (toUpperBound - toLowerBound) / (fromUpperBound - fromLowerBound)\n        return (self - fromLowerBound) * k + toLowerBound\n    }\n\n    func normalized(from: ClosedRange<Self> = 0 ... 1, to: ClosedRange<Self> = 0 ... 1) -> Self {\n        normalized(\n            fromLowerBound: from.lowerBound,\n            fromUpperBound: from.upperBound,\n            toLowerBound: to.lowerBound,\n            toUpperBound: to.upperBound\n        )\n    }\n}\n\nextension BinaryFloatingPoint {\n    func normalized(\n        fromLowerBound: Self = 0,\n        fromUpperBound: Self = 1,\n        toLowerBound: Self = 0,\n        toUpperBound: Self = 1\n    ) -> Self {\n        let k = (toUpperBound - toLowerBound) / (fromUpperBound - fromLowerBound)\n        return (self - fromLowerBound) * k + toLowerBound\n    }\n\n    func normalized(from: ClosedRange<Self> = 0 ... 1, to: ClosedRange<Self> = 0 ... 1) -> Self {\n        normalized(\n            fromLowerBound: from.lowerBound,\n            fromUpperBound: from.upperBound,\n            toLowerBound: to.lowerBound,\n            toUpperBound: to.upperBound\n        )\n    }\n}\n\nextension Decimal {\n    var asTruncatedDouble: Double {\n        Double(truncating: self as NSNumber)\n    }\n\n    func rounded(_ scale: Int) -> Self {\n        var roundedValue = Decimal()\n        var mutableSelf = self\n        NSDecimalRound(&roundedValue, &mutableSelf, scale, .plain)\n        return roundedValue\n    }\n}\n\nfunc formattedPercent<Value: BinaryInteger>(_ value: Value) -> String {\n    wholePercentNumberFormatter.string(from: NSNumber(value: Double(Int(value)) / 100.0))\n        ?? \"\\(value)%\"\n}\n\nextension pid_t {\n    private static var bundleIdentifierCache = LRUCache<Self, String>(countLimit: 16)\n    private static var processPathCache = LRUCache<Self, String>(countLimit: 16)\n    private static var processNameCache = LRUCache<Self, String>(countLimit: 16)\n\n    var bundleIdentifier: String? {\n        guard let bundleIdentifier = Self.bundleIdentifierCache.value(forKey: self)\n            ?? NSRunningApplication(processIdentifier: self)?.bundleIdentifier\n        else {\n            return nil\n        }\n\n        Self.bundleIdentifierCache.setValue(bundleIdentifier, forKey: self)\n\n        return bundleIdentifier\n    }\n\n    var processPath: String? {\n        if let cached = Self.processPathCache.value(forKey: self) {\n            return cached\n        }\n        guard let path = NSRunningApplication(processIdentifier: self)?.executableURL?.path else {\n            return nil\n        }\n        Self.processPathCache.setValue(path, forKey: self)\n        return path\n    }\n\n    var processName: String? {\n        if let cached = Self.processNameCache.value(forKey: self) {\n            return cached\n        }\n        guard let name = NSRunningApplication(processIdentifier: self)?.executableURL?.lastPathComponent else {\n            return nil\n        }\n        Self.processNameCache.setValue(name, forKey: self)\n        return name\n    }\n\n    var parent: pid_t? {\n        let pid = getProcessInfo(self).ppid\n\n        guard pid > 0 else {\n            return nil\n        }\n\n        return pid\n    }\n\n    var group: pid_t? {\n        let pid = getProcessInfo(self).pgid\n\n        guard pid > 0 else {\n            return nil\n        }\n\n        return pid\n    }\n}\n\nextension CGMouseButton {\n    static let back = CGMouseButton(rawValue: 3)!\n    static let forward = CGMouseButton(rawValue: 4)!\n\n    func fixedCGEventType(of eventType: CGEventType) -> CGEventType {\n        func fixed(of type: CGEventType, _ l: CGEventType, _ r: CGEventType, _ o: CGEventType) -> CGEventType {\n            guard type == l || type == r || type == o else {\n                return type\n            }\n            return self == .left ? l : self == .right ? r : o\n        }\n\n        var eventType = eventType\n        eventType = fixed(of: eventType, .leftMouseDown, .rightMouseDown, .otherMouseDown)\n        eventType = fixed(of: eventType, .leftMouseUp, .rightMouseUp, .otherMouseUp)\n        eventType = fixed(of: eventType, .leftMouseDragged, .rightMouseDragged, .otherMouseDragged)\n        return eventType\n    }\n}\n\nextension CGMouseButton: Codable {}\n\nextension Binding {\n    func `default`<UnwrappedValue>(_ value: UnwrappedValue) -> Binding<UnwrappedValue> where Value == UnwrappedValue? {\n        Binding<UnwrappedValue>(get: { wrappedValue ?? value }, set: { wrappedValue = $0 })\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/KeyboardSettingsSnapshot.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\n\n/// Main-thread snapshot of keyboard-repeat timings so event-thread code can read them without touching AppKit.\n///\n/// `NSEvent.keyRepeatDelay` / `NSEvent.keyRepeatInterval` do not auto-update; refresh at app launch and\n/// when the session becomes active.\nfinal class KeyboardSettingsSnapshot {\n    static let shared = KeyboardSettingsSnapshot()\n\n    private let lock = NSLock()\n    private var _keyRepeatDelay: TimeInterval = 0\n    private var _keyRepeatInterval: TimeInterval = 0\n\n    private init() {}\n\n    var keyRepeatDelay: TimeInterval {\n        lock.withLock { _keyRepeatDelay }\n    }\n\n    var keyRepeatInterval: TimeInterval {\n        lock.withLock { _keyRepeatInterval }\n    }\n\n    /// Call from the main thread.\n    func refresh() {\n        assert(Thread.isMainThread)\n        let delay = NSEvent.keyRepeatDelay\n        let interval = NSEvent.keyRepeatInterval\n        lock.withLock {\n            _keyRepeatDelay = delay\n            _keyRepeatInterval = interval\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Notifier.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport UserNotifications\n\nclass Notifier: NSObject {\n    static let shared = Notifier()\n\n    private let center = UNUserNotificationCenter.current()\n    private var didSetup = false\n\n    func setup() {\n        guard !didSetup else {\n            return\n        }\n        didSetup = true\n        // Only set the delegate now; request authorization lazily on first notification\n        center.delegate = self\n    }\n\n    func notify(title: String, body: String) {\n        if !didSetup {\n            center.delegate = self\n            didSetup = true\n        }\n\n        center.getNotificationSettings { [weak self] settings in\n            guard let self else {\n                return\n            }\n\n            let send: () -> Void = {\n                let content = UNMutableNotificationContent()\n                content.title = title\n                content.body = body\n\n                let request = UNNotificationRequest(\n                    identifier: UUID().uuidString,\n                    content: content,\n                    trigger: nil\n                )\n\n                self.center.add(request, withCompletionHandler: nil)\n            }\n\n            if settings.authorizationStatus == .notDetermined {\n                self.center.requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in\n                    send()\n                }\n            } else {\n                send()\n            }\n        }\n    }\n}\n\nextension Notifier: UNUserNotificationCenterDelegate {\n    func userNotificationCenter(\n        _: UNUserNotificationCenter,\n        willPresent _: UNNotification,\n        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions)\n            -> Void\n    ) {\n        // Ensure banners appear when the app is in the foreground\n        if #available(macOS 11.0, *) {\n            completionHandler([.banner, .sound, .list])\n        } else {\n            completionHandler([.alert, .sound])\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/Process.h",
    "content": "#ifndef LINEARMOUSE_PROCESS_H\n#define LINEARMOUSE_PROCESS_H\n\n#include <sys/sysctl.h>\n\ntypedef struct ProcessInfo {\n    pid_t ppid;\n    pid_t pgid;\n} ProcessInfo;\n\nProcessInfo getProcessInfo(pid_t pid);\n\n#endif /* LINEARMOUSE_PROCESS_H */\n"
  },
  {
    "path": "LinearMouse/Utilities/Process.m",
    "content": "#include \"Process.h\"\n\nProcessInfo getProcessInfo(pid_t pid) {\n    ProcessInfo pi = { 0 };\n\n    struct kinfo_proc info;\n    size_t length = sizeof(struct kinfo_proc);\n    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };\n    if (sysctl(mib, 4, &info, &length, NULL, 0) < 0 || !length)\n        return pi;\n\n    pi.ppid = info.kp_eproc.e_ppid;\n    pi.pgid = info.kp_eproc.e_pgid;\n\n    return pi;\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/ProcessEnvironment.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nenum ProcessEnvironment {\n    static var isPreview: Bool {\n        #if DEBUG\n            return ProcessInfo.processInfo.environment[\"XCODE_RUNNING_FOR_PREVIEWS\"] == \"1\"\n        #else\n            return false\n        #endif\n    }\n\n    static var isRunningTest: Bool {\n        #if DEBUG\n            return ProcessInfo.processInfo.environment[\"XCTestConfigurationFilePath\"] != nil\n        #else\n            return false\n        #endif\n    }\n\n    static var isRunningApp: Bool {\n        !(isPreview || isRunningTest)\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/WeakRef.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nclass WeakRef<T: AnyObject> {\n    weak var value: T?\n\n    init() {}\n\n    init(_ value: T) {\n        self.value = value\n    }\n}\n\nextension WeakRef: Equatable where T: Equatable {\n    static func == (lhs: WeakRef<T>, rhs: WeakRef<T>) -> Bool {\n        lhs.value == rhs.value\n    }\n}\n\nextension WeakRef: Hashable where T: Hashable {\n    func hash(into hasher: inout Hasher) {\n        hasher.combine(value)\n    }\n}\n\nextension WeakRef: CustomStringConvertible where T: CustomStringConvertible {\n    var description: String {\n        value?.description ?? \"(nil)\"\n    }\n}\n"
  },
  {
    "path": "LinearMouse/Utilities/WindowInfo.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport Foundation\n\nextension CGPoint {\n    /// Returns the owner pid of the topmost normal-level window that contains this point.\n    var topmostWindowOwnerPid: pid_t? {\n        let options = CGWindowListOption(arrayLiteral: [.excludeDesktopElements, .optionOnScreenOnly])\n        guard let windowListInfo = CGWindowListCopyWindowInfo(options, kCGNullWindowID) as NSArray? as? [[String: Any]]\n        else {\n            return nil\n        }\n\n        for windowInfo in windowListInfo {\n            // Only consider normal application windows (NSWindow.Level.normal == 0) so that\n            // overlays such as the menu bar, Dock, status-bar panels, and click-through HUDs\n            // (including our own auto-scroll indicator) don't take precedence.\n            guard let layer = windowInfo[kCGWindowLayer as String] as? Int, layer == 0 else {\n                continue\n            }\n\n            guard let boundsDictionary = windowInfo[kCGWindowBounds as String] as? NSDictionary,\n                  let bounds = CGRect(dictionaryRepresentation: boundsDictionary),\n                  bounds.contains(self) else {\n                continue\n            }\n\n            if let alpha = windowInfo[kCGWindowAlpha as String] as? Double, alpha <= 0 {\n                continue\n            }\n\n            return windowInfo[kCGWindowOwnerPID as String] as? pid_t\n        }\n\n        return nil\n    }\n}\n"
  },
  {
    "path": "LinearMouse.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 70;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t9724FACA2A3E04DE00622F5A /* KeyKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9724FAC92A3E04DE00622F5A /* KeyKit */; };\n\t\t972A5E30285D891100CB6440 /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 972A5E2F285D891100CB6440 /* Defaults */; };\n\t\t975979DB2A6BA1A700016EDF /* ObservationToken in Frameworks */ = {isa = PBXBuildFile; productRef = 975979DA2A6BA1A700016EDF /* ObservationToken */; };\n\t\t977638F9286BE9EE00A698B6 /* PublishedObject in Frameworks */ = {isa = PBXBuildFile; productRef = 977638F8286BE9EE00A698B6 /* PublishedObject */; };\n\t\t978DBCA629AB1732002259B3 /* JSONPatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 978DBCA529AB1732002259B3 /* JSONPatcher */; };\n\t\t97A7A39C28587E8C00EE4833 /* PointerKit in Frameworks */ = {isa = PBXBuildFile; productRef = 97A7A39B28587E8C00EE4833 /* PointerKit */; };\n\t\t97C5D8FF2856E3CB00CBED2D /* GestureKit in Frameworks */ = {isa = PBXBuildFile; productRef = 97C5D8FE2856E3CB00CBED2D /* GestureKit */; };\n\t\t97C97728288FC49F009094BA /* DockKit in Frameworks */ = {isa = PBXBuildFile; productRef = 97C97727288FC49F009094BA /* DockKit */; };\n\t\t97FC692F29F44D0100859859 /* AppMover in Frameworks */ = {isa = PBXBuildFile; productRef = 97FC692E29F44D0100859859 /* AppMover */; };\n\t\t97FD5B552CCDF2A600125BFE /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 97FD5B542CCDF2A600125BFE /* Sparkle */; };\n\t\tB70A58F6284F987900E5C86E /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = B70A58F5284F987900E5C86E /* LaunchAtLogin */; };\n\t\tB73AC55127C29C7C00F7D3E8 /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = B73AC55027C29C7C00F7D3E8 /* Version */; };\n\t\tB7F6C5F827A4F6A800E5400B /* LRUCache in Frameworks */ = {isa = PBXBuildFile; productRef = B7F6C5F727A4F6A800E5400B /* LRUCache */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tB7ADF9992748ED620005B02D /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = B75A06102671E9D800BEAF77 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B75A06172671E9D800BEAF77;\n\t\t\tremoteInfo = LinearMouse;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\tB716F16226BC18AB0052F551 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };\n\t\tB716F16326BC19350052F551 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = \"<group>\"; };\n\t\tB75A06182671E9D800BEAF77 /* LinearMouse.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LinearMouse.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB7ADF9952748ED620005B02D /* LinearMouseUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinearMouseUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB7CD86AB27B38B26006C5C37 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */\n\t\t973B4AE52CCDF18A0029D1CA /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {\n\t\t\tisa = PBXFileSystemSynchronizedBuildFileExceptionSet;\n\t\t\tmembershipExceptions = (\n\t\t\t\tInfo.plist,\n\t\t\t);\n\t\t\ttarget = B75A06172671E9D800BEAF77 /* LinearMouse */;\n\t\t};\n/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */\n\n/* Begin PBXFileSystemSynchronizedRootGroup section */\n\t\t973B49702CCDF1550029D1CA /* Modules */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Modules; sourceTree = \"<group>\"; };\n\t\t973B497D2CCDF15F0029D1CA /* LinearMouseUnitTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = LinearMouseUnitTests; sourceTree = \"<group>\"; };\n\t\t973B4A692CCDF18A0029D1CA /* LinearMouse */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (973B4AE52CCDF18A0029D1CA /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = LinearMouse; sourceTree = \"<group>\"; };\n/* End PBXFileSystemSynchronizedRootGroup section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tB75A06152671E9D800BEAF77 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t977638F9286BE9EE00A698B6 /* PublishedObject in Frameworks */,\n\t\t\t\t978DBCA629AB1732002259B3 /* JSONPatcher in Frameworks */,\n\t\t\t\tB70A58F6284F987900E5C86E /* LaunchAtLogin in Frameworks */,\n\t\t\t\t9724FACA2A3E04DE00622F5A /* KeyKit in Frameworks */,\n\t\t\t\t97C97728288FC49F009094BA /* DockKit in Frameworks */,\n\t\t\t\t97FD5B552CCDF2A600125BFE /* Sparkle in Frameworks */,\n\t\t\t\t97FC692F29F44D0100859859 /* AppMover in Frameworks */,\n\t\t\t\t972A5E30285D891100CB6440 /* Defaults in Frameworks */,\n\t\t\t\t97A7A39C28587E8C00EE4833 /* PointerKit in Frameworks */,\n\t\t\t\t97C5D8FF2856E3CB00CBED2D /* GestureKit in Frameworks */,\n\t\t\t\tB73AC55127C29C7C00F7D3E8 /* Version in Frameworks */,\n\t\t\t\t975979DB2A6BA1A700016EDF /* ObservationToken in Frameworks */,\n\t\t\t\tB7F6C5F827A4F6A800E5400B /* LRUCache in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB7ADF9922748ED620005B02D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t97C5D8F72856E18900CBED2D /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB75A060F2671E9D800BEAF77 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB7CD86AB27B38B26006C5C37 /* Config.xcconfig */,\n\t\t\t\t973B4A692CCDF18A0029D1CA /* LinearMouse */,\n\t\t\t\t973B49702CCDF1550029D1CA /* Modules */,\n\t\t\t\tB716F16326BC19350052F551 /* LICENSE */,\n\t\t\t\tB716F16226BC18AB0052F551 /* README.md */,\n\t\t\t\t973B497D2CCDF15F0029D1CA /* LinearMouseUnitTests */,\n\t\t\t\tB75A06192671E9D800BEAF77 /* Products */,\n\t\t\t\t97C5D8F72856E18900CBED2D /* Frameworks */,\n\t\t\t);\n\t\t\tindentWidth = 4;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 4;\n\t\t};\n\t\tB75A06192671E9D800BEAF77 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB75A06182671E9D800BEAF77 /* LinearMouse.app */,\n\t\t\t\tB7ADF9952748ED620005B02D /* LinearMouseUnitTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tB75A06172671E9D800BEAF77 /* LinearMouse */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B75A062B2671E9DA00BEAF77 /* Build configuration list for PBXNativeTarget \"LinearMouse\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB75A06142671E9D800BEAF77 /* Sources */,\n\t\t\t\tB75A06152671E9D800BEAF77 /* Frameworks */,\n\t\t\t\tB75A06162671E9D800BEAF77 /* Resources */,\n\t\t\t\tB70A58F7284F988B00E5C86E /* Copy “Launch at Login Helper” */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tfileSystemSynchronizedGroups = (\n\t\t\t\t973B4A692CCDF18A0029D1CA /* LinearMouse */,\n\t\t\t);\n\t\t\tname = LinearMouse;\n\t\t\tpackageProductDependencies = (\n\t\t\t\tB7F6C5F727A4F6A800E5400B /* LRUCache */,\n\t\t\t\tB73AC55027C29C7C00F7D3E8 /* Version */,\n\t\t\t\tB70A58F5284F987900E5C86E /* LaunchAtLogin */,\n\t\t\t\t97C5D8FE2856E3CB00CBED2D /* GestureKit */,\n\t\t\t\t97A7A39B28587E8C00EE4833 /* PointerKit */,\n\t\t\t\t972A5E2F285D891100CB6440 /* Defaults */,\n\t\t\t\t977638F8286BE9EE00A698B6 /* PublishedObject */,\n\t\t\t\t97C97727288FC49F009094BA /* DockKit */,\n\t\t\t\t978DBCA529AB1732002259B3 /* JSONPatcher */,\n\t\t\t\t97FC692E29F44D0100859859 /* AppMover */,\n\t\t\t\t9724FAC92A3E04DE00622F5A /* KeyKit */,\n\t\t\t\t975979DA2A6BA1A700016EDF /* ObservationToken */,\n\t\t\t\t97FD5B542CCDF2A600125BFE /* Sparkle */,\n\t\t\t);\n\t\t\tproductName = LinearMouse;\n\t\t\tproductReference = B75A06182671E9D800BEAF77 /* LinearMouse.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tB7ADF9942748ED620005B02D /* LinearMouseUnitTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B7ADF99D2748ED620005B02D /* Build configuration list for PBXNativeTarget \"LinearMouseUnitTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB7ADF9912748ED620005B02D /* Sources */,\n\t\t\t\tB7ADF9922748ED620005B02D /* Frameworks */,\n\t\t\t\tB7ADF9932748ED620005B02D /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tB7ADF99A2748ED620005B02D /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tfileSystemSynchronizedGroups = (\n\t\t\t\t973B497D2CCDF15F0029D1CA /* LinearMouseUnitTests */,\n\t\t\t);\n\t\t\tname = LinearMouseUnitTests;\n\t\t\tproductName = LinearMouseUnitTests;\n\t\t\tproductReference = B7ADF9952748ED620005B02D /* LinearMouseUnitTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tB75A06102671E9D800BEAF77 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1310;\n\t\t\t\tLastUpgradeCheck = 1420;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tB75A06172671E9D800BEAF77 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.5;\n\t\t\t\t\t};\n\t\t\t\t\tB7ADF9942748ED620005B02D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 13.1;\n\t\t\t\t\t\tTestTargetID = B75A06172671E9D800BEAF77;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = B75A06132671E9D800BEAF77 /* Build configuration list for PBXProject \"LinearMouse\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t\t\"zh-Hans\",\n\t\t\t\t\"zh-Hant\",\n\t\t\t\tru,\n\t\t\t\tde,\n\t\t\t\taf,\n\t\t\t\thu,\n\t\t\t\tko,\n\t\t\t\tit,\n\t\t\t\tno,\n\t\t\t\tnb,\n\t\t\t\tro,\n\t\t\t\tcs,\n\t\t\t\tel,\n\t\t\t\tes,\n\t\t\t\tpt,\n\t\t\t\tda,\n\t\t\t\tvi,\n\t\t\t\tja,\n\t\t\t\tca,\n\t\t\t\tpl,\n\t\t\t\t\"pt-BR\",\n\t\t\t\tuk,\n\t\t\t\the,\n\t\t\t\tsr,\n\t\t\t\ttr,\n\t\t\t\tar,\n\t\t\t\tsv,\n\t\t\t\tfi,\n\t\t\t\tfr,\n\t\t\t\tnl,\n\t\t\t\tsk,\n\t\t\t\tmy,\n\t\t\t\t\"zh-Hant-HK\",\n\t\t\t);\n\t\t\tmainGroup = B75A060F2671E9D800BEAF77;\n\t\t\tpackageReferences = (\n\t\t\t\tB784292B278DB06600D207F0 /* XCRemoteSwiftPackageReference \"Sparkle\" */,\n\t\t\t\tB7F6C5F627A4F6A800E5400B /* XCRemoteSwiftPackageReference \"LRUCache\" */,\n\t\t\t\tB73AC54F27C29C7C00F7D3E8 /* XCRemoteSwiftPackageReference \"Version\" */,\n\t\t\t\tB70A58F4284F987900E5C86E /* XCRemoteSwiftPackageReference \"LaunchAtLogin\" */,\n\t\t\t\t972A5E2E285D891100CB6440 /* XCRemoteSwiftPackageReference \"Defaults\" */,\n\t\t\t\t977638F7286BE9EE00A698B6 /* XCRemoteSwiftPackageReference \"PublishedObject\" */,\n\t\t\t\t978DBCA429AB1732002259B3 /* XCRemoteSwiftPackageReference \"JSONPatcher\" */,\n\t\t\t\t97FC692B29F44CE000859859 /* XCRemoteSwiftPackageReference \"AppMover\" */,\n\t\t\t);\n\t\t\tproductRefGroup = B75A06192671E9D800BEAF77 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tB75A06172671E9D800BEAF77 /* LinearMouse */,\n\t\t\t\tB7ADF9942748ED620005B02D /* LinearMouseUnitTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tB75A06162671E9D800BEAF77 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB7ADF9932748ED620005B02D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\tB70A58F7284F988B00E5C86E /* Copy “Launch at Login Helper” */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 8;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Copy “Launch at Login Helper”\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${BUILT_PRODUCTS_DIR}/LaunchAtLogin_LaunchAtLogin.bundle/Contents/Resources/copy-helper-swiftpm.sh\\\"\\n\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tB75A06142671E9D800BEAF77 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB7ADF9912748ED620005B02D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tB7ADF99A2748ED620005B02D /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B75A06172671E9D800BEAF77 /* LinearMouse */;\n\t\t\ttargetProxy = B7ADF9992748ED620005B02D /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\tB75A06292671E9DA00BEAF77 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B7CD86AB27B38B26006C5C37 /* Config.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB75A062A2671E9DA00BEAF77 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B7CD86AB27B38B26006C5C37 /* Config.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB75A062C2671E9DA00BEAF77 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = LinearMouse/LinearMouse.entitlements;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\";\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tINFOPLIST_FILE = LinearMouse/Info.plist;\n\t\t\t\tINFOPLIST_KEY_LSApplicationCategoryType = \"public.app-category.utilities\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"LinearMouse/LinearMouse-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB75A062D2671E9DA00BEAF77 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = LinearMouse/LinearMouse.entitlements;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_ASSET_PATHS = \"\";\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tENABLE_PREVIEWS = YES;\n\t\t\t\tINFOPLIST_FILE = LinearMouse/Info.plist;\n\t\t\t\tINFOPLIST_KEY_LSApplicationCategoryType = \"public.app-category.utilities\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"LinearMouse/LinearMouse-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB7ADF99B2748ED620005B02D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++17\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.lujjjh.LinearMouseUnitTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/LinearMouse.app/Contents/MacOS/LinearMouse\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB7ADF99C2748ED620005B02D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++17\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.lujjjh.LinearMouseUnitTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/LinearMouse.app/Contents/MacOS/LinearMouse\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tB75A06132671E9D800BEAF77 /* Build configuration list for PBXProject \"LinearMouse\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB75A06292671E9DA00BEAF77 /* Debug */,\n\t\t\t\tB75A062A2671E9DA00BEAF77 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB75A062B2671E9DA00BEAF77 /* Build configuration list for PBXNativeTarget \"LinearMouse\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB75A062C2671E9DA00BEAF77 /* Debug */,\n\t\t\t\tB75A062D2671E9DA00BEAF77 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB7ADF99D2748ED620005B02D /* Build configuration list for PBXNativeTarget \"LinearMouseUnitTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB7ADF99B2748ED620005B02D /* Debug */,\n\t\t\t\tB7ADF99C2748ED620005B02D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCRemoteSwiftPackageReference section */\n\t\t972A5E2E285D891100CB6440 /* XCRemoteSwiftPackageReference \"Defaults\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/sindresorhus/Defaults\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n\t\t977638F7286BE9EE00A698B6 /* XCRemoteSwiftPackageReference \"PublishedObject\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/Amzd/PublishedObject\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 0.2.0;\n\t\t\t};\n\t\t};\n\t\t978DBCA429AB1732002259B3 /* XCRemoteSwiftPackageReference \"JSONPatcher\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/linearmouse/JSONPatcher.git\";\n\t\t\trequirement = {\n\t\t\t\tbranch = main;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n\t\t97FC692B29F44CE000859859 /* XCRemoteSwiftPackageReference \"AppMover\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/linearmouse/AppMover\";\n\t\t\trequirement = {\n\t\t\t\tbranch = master;\n\t\t\t\tkind = branch;\n\t\t\t};\n\t\t};\n\t\tB70A58F4284F987900E5C86E /* XCRemoteSwiftPackageReference \"LaunchAtLogin\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/sindresorhus/LaunchAtLogin\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 5.0.0;\n\t\t\t};\n\t\t};\n\t\tB73AC54F27C29C7C00F7D3E8 /* XCRemoteSwiftPackageReference \"Version\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/mrackwitz/Version.git\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 0.8.0;\n\t\t\t};\n\t\t};\n\t\tB784292B278DB06600D207F0 /* XCRemoteSwiftPackageReference \"Sparkle\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/lujjjh/Sparkle\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 2.0.0;\n\t\t\t};\n\t\t};\n\t\tB7F6C5F627A4F6A800E5400B /* XCRemoteSwiftPackageReference \"LRUCache\" */ = {\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = \"https://github.com/nicklockwood/LRUCache.git\";\n\t\t\trequirement = {\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = 1.0.0;\n\t\t\t};\n\t\t};\n/* End XCRemoteSwiftPackageReference section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\t9724FAC92A3E04DE00622F5A /* KeyKit */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = KeyKit;\n\t\t};\n\t\t972A5E2F285D891100CB6440 /* Defaults */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 972A5E2E285D891100CB6440 /* XCRemoteSwiftPackageReference \"Defaults\" */;\n\t\t\tproductName = Defaults;\n\t\t};\n\t\t975979DA2A6BA1A700016EDF /* ObservationToken */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = ObservationToken;\n\t\t};\n\t\t977638F8286BE9EE00A698B6 /* PublishedObject */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 977638F7286BE9EE00A698B6 /* XCRemoteSwiftPackageReference \"PublishedObject\" */;\n\t\t\tproductName = PublishedObject;\n\t\t};\n\t\t978DBCA529AB1732002259B3 /* JSONPatcher */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 978DBCA429AB1732002259B3 /* XCRemoteSwiftPackageReference \"JSONPatcher\" */;\n\t\t\tproductName = JSONPatcher;\n\t\t};\n\t\t97A7A39B28587E8C00EE4833 /* PointerKit */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = PointerKit;\n\t\t};\n\t\t97C5D8FE2856E3CB00CBED2D /* GestureKit */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = GestureKit;\n\t\t};\n\t\t97C97727288FC49F009094BA /* DockKit */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = DockKit;\n\t\t};\n\t\t97FC692E29F44D0100859859 /* AppMover */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 97FC692B29F44CE000859859 /* XCRemoteSwiftPackageReference \"AppMover\" */;\n\t\t\tproductName = AppMover;\n\t\t};\n\t\t97FD5B542CCDF2A600125BFE /* Sparkle */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = B784292B278DB06600D207F0 /* XCRemoteSwiftPackageReference \"Sparkle\" */;\n\t\t\tproductName = Sparkle;\n\t\t};\n\t\tB70A58F5284F987900E5C86E /* LaunchAtLogin */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = B70A58F4284F987900E5C86E /* XCRemoteSwiftPackageReference \"LaunchAtLogin\" */;\n\t\t\tproductName = LaunchAtLogin;\n\t\t};\n\t\tB73AC55027C29C7C00F7D3E8 /* Version */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = B73AC54F27C29C7C00F7D3E8 /* XCRemoteSwiftPackageReference \"Version\" */;\n\t\t\tproductName = Version;\n\t\t};\n\t\tB7F6C5F727A4F6A800E5400B /* LRUCache */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = B7F6C5F627A4F6A800E5400B /* XCRemoteSwiftPackageReference \"LRUCache\" */;\n\t\t\tproductName = LRUCache;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = B75A06102671E9D800BEAF77 /* Project object */;\n}\n"
  },
  {
    "path": "LinearMouse.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "LinearMouse.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "LinearMouse.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved",
    "content": "{\n  \"pins\" : [\n    {\n      \"identity\" : \"appmover\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/linearmouse/AppMover\",\n      \"state\" : {\n        \"branch\" : \"master\",\n        \"revision\" : \"fbd0e88e24b606245beac62da0b8a30c2b905934\"\n      }\n    },\n    {\n      \"identity\" : \"defaults\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/sindresorhus/Defaults\",\n      \"state\" : {\n        \"branch\" : \"main\",\n        \"revision\" : \"8584d1d6ed36c195258977f2ed0cf95357efb160\"\n      }\n    },\n    {\n      \"identity\" : \"jsonpatcher\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/linearmouse/JSONPatcher.git\",\n      \"state\" : {\n        \"branch\" : \"main\",\n        \"revision\" : \"fef582b56aff502305e4dbcfabf76cb57b5d4e15\"\n      }\n    },\n    {\n      \"identity\" : \"launchatlogin\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/sindresorhus/LaunchAtLogin\",\n      \"state\" : {\n        \"revision\" : \"7ad6331f9c38953eb1ce8737758e18f7607e984a\",\n        \"version\" : \"5.0.0\"\n      }\n    },\n    {\n      \"identity\" : \"lrucache\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/nicklockwood/LRUCache.git\",\n      \"state\" : {\n        \"revision\" : \"6d2b5246c9c98dcd498552bb22f08d55b12a8371\",\n        \"version\" : \"1.0.4\"\n      }\n    },\n    {\n      \"identity\" : \"publishedobject\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/Amzd/PublishedObject\",\n      \"state\" : {\n        \"revision\" : \"e61bfde22832ba8dfe9f8be2561838a1512e38af\",\n        \"version\" : \"0.2.0\"\n      }\n    },\n    {\n      \"identity\" : \"sparkle\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/lujjjh/Sparkle\",\n      \"state\" : {\n        \"revision\" : \"f65abe543fffa92611b8066692e694f92d3cd68f\",\n        \"version\" : \"2.4.0\"\n      }\n    },\n    {\n      \"identity\" : \"version\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/mrackwitz/Version.git\",\n      \"state\" : {\n        \"revision\" : \"fd4b0eb5756aa7f1c33977fb626cf37d2140a3a0\",\n        \"version\" : \"0.8.0\"\n      }\n    }\n  ],\n  \"version\" : 2\n}\n"
  },
  {
    "path": "LinearMouse.xcodeproj/xcshareddata/xcschemes/LinearMouse.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1420\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"B75A06172671E9D800BEAF77\"\n               BuildableName = \"LinearMouse.app\"\n               BlueprintName = \"LinearMouse\"\n               ReferencedContainer = \"container:LinearMouse.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"B7ADF9942748ED620005B02D\"\n               BuildableName = \"LinearMouseUnitTests.xctest\"\n               BlueprintName = \"LinearMouseUnitTests\"\n               ReferencedContainer = \"container:LinearMouse.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"B75A06172671E9D800BEAF77\"\n            BuildableName = \"LinearMouse.app\"\n            BlueprintName = \"LinearMouse\"\n            ReferencedContainer = \"container:LinearMouse.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"B75A06172671E9D800BEAF77\"\n            BuildableName = \"LinearMouse.app\"\n            BlueprintName = \"LinearMouse\"\n            ReferencedContainer = \"container:LinearMouse.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "LinearMouseUnitTests/Device/InputReportHandlerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class InputReportHandlerTests: XCTestCase {\n    /// Captures emissions from the handlers so tests can assert against them without\n    /// posting real `otherMouseDown` events into the OS.\n    private final class EmissionRecorder {\n        private(set) var events: [(button: Int, down: Bool)] = []\n\n        var emit: MouseButtonEmitter {\n            { [weak self] button, down in\n                self?.events.append((button, down))\n            }\n        }\n    }\n\n    // MARK: - InputReportContext Tests\n\n    func testContextInitialization() {\n        let report = Data([0x00, 0x18, 0x00])\n        let context = InputReportContext(report: report, lastButtonStates: 0x00)\n\n        XCTAssertEqual(context.report, report)\n        XCTAssertEqual(context.lastButtonStates, 0x00)\n    }\n\n    func testContextMutation() {\n        let context = InputReportContext(report: Data(), lastButtonStates: 0x00)\n        context.lastButtonStates = 0x18\n\n        XCTAssertEqual(context.lastButtonStates, 0x18)\n    }\n\n    // MARK: - GenericSideButtonHandler Tests\n\n    func testGenericHandlerMatchesMiMouse() {\n        let handler = GenericSideButtonHandler()\n\n        XCTAssertTrue(handler.matches(vendorID: 0x2717, productID: 0x5014))\n    }\n\n    func testGenericHandlerMatchesDeluxMouse() {\n        let handler = GenericSideButtonHandler()\n\n        XCTAssertTrue(handler.matches(vendorID: 0x248A, productID: 0x8266))\n    }\n\n    func testGenericHandlerDoesNotMatchUnknownDevice() {\n        let handler = GenericSideButtonHandler()\n\n        XCTAssertFalse(handler.matches(vendorID: 0x1234, productID: 0x5678))\n    }\n\n    func testGenericHandlerDoesNotAlwaysNeedReportObservation() {\n        let handler = GenericSideButtonHandler()\n\n        XCTAssertFalse(handler.alwaysNeedsReportObservation())\n    }\n\n    func testGenericHandlerCallsNext() {\n        let handler = GenericSideButtonHandler { _, _ in }\n        let context = InputReportContext(report: Data([0x00, 0x00]), lastButtonStates: 0x00)\n\n        var nextCalled = false\n        handler.handleReport(context) { _ in\n            nextCalled = true\n        }\n\n        XCTAssertTrue(nextCalled)\n    }\n\n    func testGenericHandlerCallsNextEvenWithShortReport() {\n        let handler = GenericSideButtonHandler { _, _ in }\n        let context = InputReportContext(report: Data([0x00]), lastButtonStates: 0x00)\n\n        var nextCalled = false\n        handler.handleReport(context) { _ in\n            nextCalled = true\n        }\n\n        XCTAssertTrue(nextCalled)\n    }\n\n    func testGenericHandlerUpdatesButtonStates() {\n        let recorder = EmissionRecorder()\n        let handler = GenericSideButtonHandler(emit: recorder.emit)\n        // Button 3 pressed: bit 3 set (0x08)\n        let context = InputReportContext(report: Data([0x00, 0x08]), lastButtonStates: 0x00)\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x08)\n    }\n\n    func testGenericHandlerDetectsButton3Toggle() {\n        let recorder = EmissionRecorder()\n        let handler = GenericSideButtonHandler(emit: recorder.emit)\n        // Button 3 pressed: bit 3 set (0x08)\n        let context = InputReportContext(report: Data([0x00, 0x08]), lastButtonStates: 0x00)\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x08)\n        XCTAssertEqual(recorder.events.map(\\.button), [3])\n        XCTAssertEqual(recorder.events.map(\\.down), [true])\n    }\n\n    func testGenericHandlerEmitsButton3ReleaseOnUp() {\n        let recorder = EmissionRecorder()\n        let handler = GenericSideButtonHandler(emit: recorder.emit)\n        let context = InputReportContext(report: Data([0x00, 0x00]), lastButtonStates: 0x08)\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x00)\n        XCTAssertEqual(recorder.events.map(\\.button), [3])\n        XCTAssertEqual(recorder.events.map(\\.down), [false])\n    }\n\n    func testGenericHandlerDetectsButton4Toggle() {\n        let recorder = EmissionRecorder()\n        let handler = GenericSideButtonHandler(emit: recorder.emit)\n        // Button 4 pressed: bit 4 set (0x10)\n        let context = InputReportContext(report: Data([0x00, 0x10]), lastButtonStates: 0x00)\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x10)\n        XCTAssertEqual(recorder.events.map(\\.button), [4])\n        XCTAssertEqual(recorder.events.map(\\.down), [true])\n    }\n\n    func testGenericHandlerDetectsBothButtonsToggle() {\n        let recorder = EmissionRecorder()\n        let handler = GenericSideButtonHandler(emit: recorder.emit)\n        // Both buttons pressed: bits 3 and 4 set (0x18)\n        let context = InputReportContext(report: Data([0x00, 0x18]), lastButtonStates: 0x00)\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x18)\n        XCTAssertEqual(recorder.events.map(\\.button), [3, 4])\n        XCTAssertEqual(recorder.events.map(\\.down), [true, true])\n    }\n\n    func testGenericHandlerNoChangeWhenNoToggle() {\n        let recorder = EmissionRecorder()\n        let handler = GenericSideButtonHandler(emit: recorder.emit)\n        // Same state as before\n        let context = InputReportContext(report: Data([0x00, 0x08]), lastButtonStates: 0x08)\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x08)\n        XCTAssertTrue(recorder.events.isEmpty)\n    }\n\n    // MARK: - KensingtonSlimbladeHandler Tests\n\n    func testSlimbladeHandlerMatchesSlimblade() {\n        let handler = KensingtonSlimbladeHandler()\n\n        XCTAssertTrue(handler.matches(vendorID: 0x047D, productID: 0x2041))\n    }\n\n    func testSlimbladeHandlerDoesNotMatchOtherDevice() {\n        let handler = KensingtonSlimbladeHandler()\n\n        XCTAssertFalse(handler.matches(vendorID: 0x1234, productID: 0x5678))\n    }\n\n    func testSlimbladeHandlerAlwaysNeedsReportObservation() {\n        let handler = KensingtonSlimbladeHandler()\n\n        XCTAssertTrue(handler.alwaysNeedsReportObservation())\n    }\n\n    func testSlimbladeHandlerCallsNext() {\n        let handler = KensingtonSlimbladeHandler { _, _ in }\n        let context = InputReportContext(\n            report: Data([0x00, 0x00, 0x00, 0x00, 0x00]),\n            lastButtonStates: 0x00\n        )\n\n        var nextCalled = false\n        handler.handleReport(context) { _ in\n            nextCalled = true\n        }\n\n        XCTAssertTrue(nextCalled)\n    }\n\n    func testSlimbladeHandlerCallsNextEvenWithShortReport() {\n        let handler = KensingtonSlimbladeHandler { _, _ in }\n        let context = InputReportContext(report: Data([0x00, 0x00]), lastButtonStates: 0x00)\n\n        var nextCalled = false\n        handler.handleReport(context) { _ in\n            nextCalled = true\n        }\n\n        XCTAssertTrue(nextCalled)\n    }\n\n    func testSlimbladeHandlerDetectsTopLeftButton() {\n        let recorder = EmissionRecorder()\n        let handler = KensingtonSlimbladeHandler(emit: recorder.emit)\n        // Top left button pressed: bit 0 set in byte 4\n        let context = InputReportContext(\n            report: Data([0x00, 0x00, 0x00, 0x00, 0x01]),\n            lastButtonStates: 0x00\n        )\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x01)\n        XCTAssertEqual(recorder.events.map(\\.button), [3])\n        XCTAssertEqual(recorder.events.map(\\.down), [true])\n    }\n\n    func testSlimbladeHandlerEmitsTopLeftReleaseOnUp() {\n        let recorder = EmissionRecorder()\n        let handler = KensingtonSlimbladeHandler(emit: recorder.emit)\n        let context = InputReportContext(\n            report: Data([0x00, 0x00, 0x00, 0x00, 0x00]),\n            lastButtonStates: 0x01\n        )\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x00)\n        XCTAssertEqual(recorder.events.map(\\.button), [3])\n        XCTAssertEqual(recorder.events.map(\\.down), [false])\n    }\n\n    func testSlimbladeHandlerDetectsTopRightButton() {\n        let recorder = EmissionRecorder()\n        let handler = KensingtonSlimbladeHandler(emit: recorder.emit)\n        // Top right button pressed: bit 1 set in byte 4\n        let context = InputReportContext(\n            report: Data([0x00, 0x00, 0x00, 0x00, 0x02]),\n            lastButtonStates: 0x00\n        )\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x02)\n        XCTAssertEqual(recorder.events.map(\\.button), [4])\n        XCTAssertEqual(recorder.events.map(\\.down), [true])\n    }\n\n    func testSlimbladeHandlerDetectsBothTopButtons() {\n        let recorder = EmissionRecorder()\n        let handler = KensingtonSlimbladeHandler(emit: recorder.emit)\n        // Both top buttons pressed: bits 0 and 1 set in byte 4\n        let context = InputReportContext(\n            report: Data([0x00, 0x00, 0x00, 0x00, 0x03]),\n            lastButtonStates: 0x00\n        )\n\n        handler.handleReport(context) { _ in }\n\n        XCTAssertEqual(context.lastButtonStates, 0x03)\n        XCTAssertEqual(recorder.events.map(\\.button), [3, 4])\n        XCTAssertEqual(recorder.events.map(\\.down), [true, true])\n    }\n\n    // MARK: - InputReportHandlerRegistry Tests\n\n    func testRegistryFindsMiMouseHandler() {\n        let handlers = InputReportHandlerRegistry.handlers(for: 0x2717, productID: 0x5014)\n\n        XCTAssertEqual(handlers.count, 1)\n        XCTAssertTrue(handlers.first is GenericSideButtonHandler)\n    }\n\n    func testRegistryFindsSlimbladeHandler() {\n        let handlers = InputReportHandlerRegistry.handlers(for: 0x047D, productID: 0x2041)\n\n        XCTAssertEqual(handlers.count, 1)\n        XCTAssertTrue(handlers.first is KensingtonSlimbladeHandler)\n    }\n\n    func testRegistryReturnsEmptyForUnknownDevice() {\n        let handlers = InputReportHandlerRegistry.handlers(for: 0x1234, productID: 0x5678)\n\n        XCTAssertTrue(handlers.isEmpty)\n    }\n\n    // MARK: - Handler Chain Tests\n\n    func testHandlerChainExecutesInOrder() {\n        var executionOrder: [String] = []\n\n        let context = InputReportContext(report: Data([0x00, 0x00]), lastButtonStates: 0x00)\n\n        // Create a simple chain manually\n        let handler1 = MockHandler(name: \"first\") { executionOrder.append($0) }\n        let handler2 = MockHandler(name: \"second\") { executionOrder.append($0) }\n\n        let handlers: [InputReportHandler] = [handler1, handler2]\n\n        let chain = handlers.reversed().reduce({ (_: InputReportContext) in }) { next, handler in\n            { context in handler.handleReport(context, next: next) }\n        }\n        chain(context)\n\n        XCTAssertEqual(executionOrder, [\"first\", \"second\"])\n    }\n\n    func testHandlerChainCanBeInterrupted() {\n        var executionOrder: [String] = []\n\n        let context = InputReportContext(report: Data([0x00, 0x00]), lastButtonStates: 0x00)\n\n        // Create a chain where first handler doesn't call next\n        let handler1 = MockHandler(name: \"first\", callNext: false) { executionOrder.append($0) }\n        let handler2 = MockHandler(name: \"second\") { executionOrder.append($0) }\n\n        let handlers: [InputReportHandler] = [handler1, handler2]\n\n        let chain = handlers.reversed().reduce({ (_: InputReportContext) in }) { next, handler in\n            { context in handler.handleReport(context, next: next) }\n        }\n        chain(context)\n\n        XCTAssertEqual(executionOrder, [\"first\"])\n    }\n\n    func testHandlerChainPassesContextThrough() {\n        let context = InputReportContext(report: Data([0x00, 0x00]), lastButtonStates: 0x00)\n\n        let handler1 = MockHandler(name: \"first\", modifyState: 0x01) { _ in }\n        let handler2 = MockHandler(name: \"second\", modifyState: 0x02) { _ in }\n\n        let handlers: [InputReportHandler] = [handler1, handler2]\n\n        let chain = handlers.reversed().reduce({ (_: InputReportContext) in }) { next, handler in\n            { context in handler.handleReport(context, next: next) }\n        }\n        chain(context)\n\n        // Both handlers should have modified the state\n        XCTAssertEqual(context.lastButtonStates, 0x03)\n    }\n}\n\n// MARK: - Mock Handler for Testing\n\nprivate struct MockHandler: InputReportHandler {\n    let name: String\n    let callNext: Bool\n    let modifyState: UInt8\n    let onExecute: (String) -> Void\n\n    init(name: String, callNext: Bool = true, modifyState: UInt8 = 0, onExecute: @escaping (String) -> Void) {\n        self.name = name\n        self.callNext = callNext\n        self.modifyState = modifyState\n        self.onExecute = onExecute\n    }\n\n    func matches(vendorID _: Int, productID _: Int) -> Bool {\n        true\n    }\n\n    func handleReport(_ context: InputReportContext, next: (InputReportContext) -> Void) {\n        onExecute(name)\n        context.lastButtonStates |= modifyState\n\n        if callNext {\n            next(context)\n        }\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Device/VendorSpecificDeviceMetadataTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\n@testable import LinearMouse\nimport PointerKit\nimport XCTest\n\nfinal class VendorSpecificDeviceMetadataTests: XCTestCase {\n    func testMatcherMatchesVendorAndTransport() {\n        let matcher = VendorSpecificDeviceMatcher(\n            vendorID: 0x046D,\n            productIDs: [0xB015],\n            transports: [PointerDeviceTransportName.bluetoothLowEnergy]\n        )\n\n        let device = MockVendorSpecificDeviceContext(\n            vendorID: 0x046D,\n            productID: 0xB015,\n            transport: PointerDeviceTransportName.bluetoothLowEnergy\n        )\n\n        XCTAssertTrue(matcher.matches(device: device))\n    }\n\n    func testMatcherRejectsUnknownTransport() {\n        let matcher = VendorSpecificDeviceMatcher(\n            vendorID: 0x046D,\n            productIDs: nil,\n            transports: [PointerDeviceTransportName.usb]\n        )\n\n        let device = MockVendorSpecificDeviceContext(\n            vendorID: 0x046D,\n            productID: 0xB015,\n            transport: PointerDeviceTransportName.bluetoothLowEnergy\n        )\n\n        XCTAssertFalse(matcher.matches(device: device))\n    }\n\n    func testLogitechProviderMatchesLogitechDeviceShape() {\n        let provider = LogitechHIDPPDeviceMetadataProvider()\n        let device = MockVendorSpecificDeviceContext(\n            vendorID: 0x046D,\n            productID: 0xB015,\n            transport: PointerDeviceTransportName.bluetoothLowEnergy,\n            maxInputReportSize: 20,\n            maxOutputReportSize: 20\n        )\n\n        XCTAssertTrue(provider.matches(device: device))\n    }\n\n    func testReceiverLogicalDeviceIdentityUsesAllFieldsForEquality() {\n        let lhs = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: 50\n        )\n        let rhs = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .trackball,\n            name: \"Mouse B\",\n            serialNumber: \"BBBB\",\n            productID: 0x5678,\n            batteryLevel: 80\n        )\n\n        XCTAssertNotEqual(lhs, rhs)\n    }\n\n    func testReceiverLogicalDeviceIdentityCanDetectSameLogicalDevice() {\n        let lhs = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: 50\n        )\n        let rhs = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .trackball,\n            name: \"Mouse B\",\n            serialNumber: \"BBBB\",\n            productID: 0x5678,\n            batteryLevel: 80\n        )\n\n        XCTAssertTrue(lhs.isSameLogicalDevice(as: rhs))\n    }\n\n    func testParseReceiverConnectionNotificationTracksConnectState() {\n        let notification = LogitechHIDPPDeviceMetadataProvider.parseReceiverConnectionNotification([\n            0x10, 0x02, 0x41, 0x00, 0x02, 0x00, 0x00\n        ])\n\n        XCTAssertEqual(notification?.slot, 2)\n        XCTAssertEqual(notification?.snapshot, .init(isConnected: true, kind: 0x02))\n    }\n\n    func testParseConnectedDeviceCountReadsReceiverConnectionRegister() {\n        XCTAssertEqual(\n            LogitechHIDPPDeviceMetadataProvider.parseConnectedDeviceCount([0x10, 0xFF, 0x81, 0x02, 0x00, 0x01, 0x00]),\n            1\n        )\n    }\n\n    func testLogitechDivertedButtonsNotificationMatchesGestureButtonEvent() {\n        XCTAssertTrue(\n            LogitechReprogrammableControlsMonitor.isDivertedButtonsNotification(\n                [0x10, 0x02, 0x05, 0x08, 0x00, 0xC3, 0x00],\n                featureIndex: 0x05,\n                slot: 0x02\n            )\n        )\n    }\n\n    func testLogitechDivertedButtonsNotificationParsesPressedControls() {\n        XCTAssertEqual(\n            LogitechReprogrammableControlsMonitor.parseDivertedButtonsNotification([\n                0x10,\n                0x02,\n                0x05,\n                0x08,\n                0x00,\n                0xC3,\n                0x00,\n                0xC4\n            ]),\n            Set([0x00C3, 0x00C4])\n        )\n    }\n\n    func testLogitechDivertedButtonsNotificationRejectsWrongSlot() {\n        XCTAssertFalse(\n            LogitechReprogrammableControlsMonitor.isDivertedButtonsNotification(\n                [0x10, 0x03, 0x05, 0x08, 0x00, 0xC3, 0x00],\n                featureIndex: 0x05,\n                slot: 0x02\n            )\n        )\n    }\n\n    func testLogitechGestureButtonControlIDsIncludeM720ThumbButton() {\n        XCTAssertTrue(LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.gestureButtonControlIDs.contains(0x00D0))\n    }\n\n    func testLogitechGestureButtonTaskIDsIncludeM720GestureTasks() {\n        XCTAssertTrue(LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.gestureButtonTaskIDs.contains(0x00AD))\n        XCTAssertTrue(LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.gestureButtonTaskIDs.contains(0x00A9))\n    }\n\n    func testLogitechVirtualControlsUseReservedVirtualButtonNumber() {\n        XCTAssertEqual(\n            LogitechHIDPPDeviceMetadataProvider.ReprogControlsV4.reservedVirtualButtonNumber,\n            0x1000\n        )\n    }\n\n    func testLogitechControlIdentityProvidesFriendlyUserVisibleName() {\n        XCTAssertEqual(\n            LogitechControlIdentity(controlID: 0x00D0, productID: nil, serialNumber: nil)\n                .userVisibleName,\n            \"Logitech Control 0x00D0\"\n        )\n        XCTAssertEqual(\n            LogitechControlIdentity(controlID: 0x1234, productID: nil, serialNumber: nil)\n                .userVisibleName,\n            \"Logitech Control 0x1234\"\n        )\n    }\n\n    func testReceiverSlotStateStoreDoesNotResurrectDisconnectedSlotFromPairingMetadata() {\n        var store = ReceiverSlotStateStore()\n        let identity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: 60\n        )\n\n        store.mergeDiscovery(.init(identities: [identity], connectionSnapshots: [\n            1: .init(isConnected: false, kind: ReceiverLogicalDeviceKind.mouse.rawValue)\n        ], liveReachableSlots: []))\n        store.mergeDiscovery(.init(identities: [identity], connectionSnapshots: [:], liveReachableSlots: []))\n\n        XCTAssertTrue(store.currentPublishedIdentities().isEmpty)\n    }\n\n    func testReceiverSlotStateStoreClearsIdentityOnReconnectAndAllowsRefresh() {\n        var store = ReceiverSlotStateStore()\n        let identity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: 60\n        )\n\n        store.mergeDiscovery(.init(identities: [identity], connectionSnapshots: [\n            1: .init(isConnected: false, kind: ReceiverLogicalDeviceKind.mouse.rawValue)\n        ], liveReachableSlots: []))\n\n        // After disconnect→connect transition, identity is cleared for refresh\n        store.mergeConnectionSnapshots([\n            1: .init(isConnected: true, kind: ReceiverLogicalDeviceKind.mouse.rawValue)\n        ])\n        XCTAssertTrue(store.needsIdentityRefresh(slot: 1))\n        XCTAssertEqual(store.currentPublishedIdentities(), [])\n\n        // After refresh, identity is restored\n        store.updateSlotIdentity(identity)\n        XCTAssertFalse(store.needsIdentityRefresh(slot: 1))\n        XCTAssertEqual(store.currentPublishedIdentities(), [identity])\n    }\n\n    func testReceiverSlotStateStoreTreatsFreshBatteryMetadataAsReconnectEvidence() {\n        var store = ReceiverSlotStateStore()\n        let disconnectedIdentity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: nil\n        )\n        let reconnectedIdentity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: 60\n        )\n\n        store.mergeDiscovery(.init(identities: [disconnectedIdentity], connectionSnapshots: [\n            1: .init(isConnected: false, kind: ReceiverLogicalDeviceKind.mouse.rawValue)\n        ], liveReachableSlots: []))\n        store.mergeDiscovery(.init(identities: [reconnectedIdentity], connectionSnapshots: [:], liveReachableSlots: []))\n\n        XCTAssertEqual(store.currentPublishedIdentities(), [reconnectedIdentity])\n    }\n\n    func testReceiverSlotStateStoreTreatsLiveReachabilityAsReconnectEvidence() {\n        var store = ReceiverSlotStateStore()\n        let identity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: nil\n        )\n\n        store.mergeDiscovery(.init(\n            identities: [identity],\n            connectionSnapshots: [1: .init(isConnected: false, kind: ReceiverLogicalDeviceKind.mouse.rawValue)],\n            liveReachableSlots: []\n        ))\n        store.mergeDiscovery(.init(\n            identities: [identity],\n            connectionSnapshots: [:],\n            liveReachableSlots: [1]\n        ))\n\n        XCTAssertEqual(store.currentPublishedIdentities(), [identity])\n    }\n\n    func testReceiverSlotStateStoreDoesNotReconnectWithoutEvidence() {\n        var store = ReceiverSlotStateStore()\n        let identity = ReceiverLogicalDeviceIdentity(\n            receiverLocationID: 0x1234,\n            slot: 1,\n            kind: .mouse,\n            name: \"Mouse A\",\n            serialNumber: \"AAAA\",\n            productID: 0x1234,\n            batteryLevel: nil\n        )\n\n        store.mergeDiscovery(.init(\n            identities: [identity],\n            connectionSnapshots: [1: .init(isConnected: false, kind: ReceiverLogicalDeviceKind.mouse.rawValue)],\n            liveReachableSlots: []\n        ))\n        store.mergeDiscovery(.init(\n            identities: [identity],\n            connectionSnapshots: [:],\n            liveReachableSlots: []\n        ))\n\n        XCTAssertTrue(store.currentPublishedIdentities().isEmpty)\n    }\n\n    func testConnectedBatteryDeviceDirectIdentityPrefersSerialNumber() {\n        let identity = ConnectedBatteryDeviceInfo.directIdentity(\n            vendorID: 0x046D,\n            productID: 0x405E,\n            serialNumber: \"ABC123\",\n            locationID: 0x1000,\n            transport: PointerDeviceTransportName.usb,\n            fallbackName: \"Mouse\"\n        )\n\n        XCTAssertEqual(identity, \"serial|1133|16478|ABC123\")\n    }\n\n    func testConnectedBatteryDeviceDirectIdentityFallsBackToLocation() {\n        let identity = ConnectedBatteryDeviceInfo.directIdentity(\n            vendorID: 0x046D,\n            productID: 0x405E,\n            serialNumber: nil,\n            locationID: 0x2000,\n            transport: PointerDeviceTransportName.usb,\n            fallbackName: \"Mouse\"\n        )\n\n        XCTAssertEqual(identity, \"location|1133|16478|8192\")\n    }\n\n    func testConnectedBatteryDeviceReceiverIdentityUsesReceiverAndSlot() {\n        XCTAssertEqual(\n            ConnectedBatteryDeviceInfo.receiverIdentity(receiverLocationID: 0x1234, slot: 2),\n            \"receiver|4660|2\"\n        )\n    }\n\n    func testVendorSpecificDeviceMetadataSupportsEquality() {\n        XCTAssertEqual(\n            VendorSpecificDeviceMetadata(name: \"MX Master 3\", batteryLevel: 50),\n            VendorSpecificDeviceMetadata(name: \"MX Master 3\", batteryLevel: 50)\n        )\n        XCTAssertNotEqual(\n            VendorSpecificDeviceMetadata(name: \"MX Master 3\", batteryLevel: 50),\n            VendorSpecificDeviceMetadata(name: \"MX Master 3\", batteryLevel: 80)\n        )\n    }\n\n    func testDeviceManagerDisplayNameUsesSinglePairedDeviceName() {\n        let identities = [\n            ReceiverLogicalDeviceIdentity(\n                receiverLocationID: 1,\n                slot: 1,\n                kind: .mouse,\n                name: \"M720 Triathlon\",\n                serialNumber: nil,\n                productID: nil,\n                batteryLevel: 50\n            )\n        ]\n\n        XCTAssertEqual(\n            DeviceManager.displayName(baseName: \"USB Receiver\", pairedDevices: identities),\n            \"USB Receiver (M720 Triathlon)\"\n        )\n    }\n\n    func testDeviceManagerDisplayNameUsesDeviceCountForMultiplePairedDevices() {\n        let identities = [\n            ReceiverLogicalDeviceIdentity(\n                receiverLocationID: 1,\n                slot: 1,\n                kind: .mouse,\n                name: \"Mouse A\",\n                serialNumber: nil,\n                productID: nil,\n                batteryLevel: 50\n            ),\n            ReceiverLogicalDeviceIdentity(\n                receiverLocationID: 1,\n                slot: 2,\n                kind: .trackball,\n                name: \"Mouse B\",\n                serialNumber: nil,\n                productID: nil,\n                batteryLevel: 80\n            )\n        ]\n\n        let expected = String(\n            format: NSLocalizedString(\"%@ (%lld devices)\", comment: \"\"),\n            \"USB Receiver\",\n            Int64(identities.count)\n        )\n\n        XCTAssertEqual(\n            DeviceManager.displayName(baseName: \"USB Receiver\", pairedDevices: identities),\n            expected\n        )\n    }\n}\n\nprivate struct MockVendorSpecificDeviceContext: VendorSpecificDeviceContext {\n    var vendorID: Int?\n    var productID: Int?\n    var product: String?\n    var name: String\n    var serialNumber: String?\n    var transport: String?\n    var locationID: Int?\n    var primaryUsagePage: Int?\n    var primaryUsage: Int?\n    var maxInputReportSize: Int?\n    var maxOutputReportSize: Int?\n    var maxFeatureReportSize: Int?\n\n    init(\n        vendorID: Int?,\n        productID: Int?,\n        product: String? = nil,\n        name: String = \"Mock Device\",\n        serialNumber: String? = nil,\n        transport: String?,\n        locationID: Int? = nil,\n        primaryUsagePage: Int? = nil,\n        primaryUsage: Int? = nil,\n        maxInputReportSize: Int? = 20,\n        maxOutputReportSize: Int? = 20,\n        maxFeatureReportSize: Int? = 20\n    ) {\n        self.vendorID = vendorID\n        self.productID = productID\n        self.product = product\n        self.name = name\n        self.serialNumber = serialNumber\n        self.transport = transport\n        self.locationID = locationID\n        self.primaryUsagePage = primaryUsagePage\n        self.primaryUsage = primaryUsage\n        self.maxInputReportSize = maxInputReportSize\n        self.maxOutputReportSize = maxOutputReportSize\n        self.maxFeatureReportSize = maxFeatureReportSize\n    }\n\n    func performSynchronousOutputReportRequest(\n        _: Data,\n        timeout _: TimeInterval,\n        matching _: @escaping (Data) -> Bool\n    ) -> Data? {\n        nil\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/AutoScrollTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport ApplicationServices\n@testable import LinearMouse\nimport XCTest\n\nfinal class AutoScrollTransformerTests: XCTestCase {\n    func testPressableActivationElementAcceptsExplicitControls() {\n        XCTAssertTrue(AutoScrollTransformer.isPressableActivationElement(role: \"AXLink\", actions: []))\n        XCTAssertTrue(AutoScrollTransformer.isPressableActivationElement(\n            role: \"AXButton\",\n            actions: [kAXPressAction as String]\n        ))\n        XCTAssertTrue(AutoScrollTransformer.isPressableActivationElement(\n            role: \"AXCheckBox\",\n            actions: [kAXPressAction as String]\n        ))\n        XCTAssertTrue(AutoScrollTransformer.isPressableActivationElement(\n            role: \"AXComboBox\",\n            actions: [kAXPressAction as String]\n        ))\n    }\n\n    func testPressableActivationElementRejectsGenericGroupEvenWithPressAction() {\n        XCTAssertFalse(AutoScrollTransformer.isPressableActivationElement(\n            role: \"AXGroup\",\n            actions: [kAXPressAction as String]\n        ))\n    }\n\n    func testPressableActivationElementRejectsControlWithoutPressActionWhenNeeded() {\n        XCTAssertFalse(AutoScrollTransformer.isPressableActivationElement(role: \"AXButton\", actions: []))\n        XCTAssertFalse(AutoScrollTransformer.isPressableActivationElement(\n            role: nil,\n            actions: [kAXPressAction as String]\n        ))\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/ButtonActionsTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\nimport KeyKit\n@testable import LinearMouse\nimport XCTest\n\nprivate final class RecordingKeySimulator: KeySimulating {\n    enum Event: Equatable {\n        case down([Key])\n        case up([Key])\n        case press([Key])\n        case reset\n    }\n\n    private(set) var events: [Event] = []\n\n    func down(keys: [Key], tap _: CGEventTapLocation?) throws {\n        events.append(.down(keys))\n    }\n\n    func up(keys: [Key], tap _: CGEventTapLocation?) throws {\n        events.append(.up(keys))\n    }\n\n    func press(keys: [Key], tap _: CGEventTapLocation?) throws {\n        events.append(.press(keys))\n    }\n\n    func reset() {\n        events.append(.reset)\n    }\n\n    func modifiedCGEventFlags(of _: CGEvent) -> CGEventFlags? {\n        nil\n    }\n}\n\nprivate func logitechContext(\n    _ controlID: Int,\n    pressed: Bool,\n    modifierFlags: CGEventFlags = []\n) -> LogitechEventContext {\n    .init(\n        device: nil,\n        pid: nil,\n        display: nil,\n        mouseLocation: .zero,\n        controlIdentity: .init(controlID: controlID),\n        isPressed: pressed,\n        modifierFlags: modifierFlags\n    )\n}\n\nfinal class ButtonActionsTransformerTests: XCTestCase {\n    func testLogitechControlEventMatchesGenericCommandMappingWithRightCommandFlag() {\n        let transformer = ButtonActionsTransformer(mappings: [\n            .init(\n                button: .logitechControl(.init(controlID: 0x0053)),\n                command: true,\n                action: .arg0(.none)\n            )\n        ])\n\n        let result = transformer.findLogitechMapping(for: .init(\n            device: nil,\n            pid: nil,\n            display: nil,\n            mouseLocation: .zero,\n            controlIdentity: .init(controlID: 0x0053),\n            isPressed: false,\n            modifierFlags: [.maskCommand, .init(rawValue: UInt64(NX_DEVICERCMDKEYMASK))]\n        ))\n\n        XCTAssertNotNil(result)\n    }\n\n    func testLogitechSpecificMappingWinsOverGenericMapping() {\n        let transformer = ButtonActionsTransformer(mappings: [\n            .init(\n                button: .logitechControl(.init(controlID: 0x0053, productID: 0x405E, serialNumber: nil)),\n                action: .arg0(.mouseButtonBack)\n            ),\n            .init(\n                button: .logitechControl(.init(controlID: 0x0053)),\n                action: .arg0(.auto)\n            )\n        ])\n\n        let result = transformer.findLogitechMapping(for: .init(\n            device: nil,\n            pid: nil,\n            display: nil,\n            mouseLocation: .zero,\n            controlIdentity: .init(controlID: 0x0053, productID: 0x405E, serialNumber: nil),\n            isPressed: false,\n            modifierFlags: []\n        ))\n\n        XCTAssertNotNil(result)\n        XCTAssertEqual(result?.action, Scheme.Buttons.Mapping.Action.arg0(.mouseButtonBack))\n    }\n\n    func testLogitechControlEventMatchesWithPartialIdentity() {\n        // A mapping with only controlID should match an event with full identity\n        let transformer = ButtonActionsTransformer(mappings: [\n            .init(\n                button: .logitechControl(.init(controlID: 0x00C3)),\n                action: .arg0(.none)\n            )\n        ])\n\n        let result = transformer.findLogitechMapping(for: .init(\n            device: nil,\n            pid: nil,\n            display: nil,\n            mouseLocation: .zero,\n            controlIdentity: .init(\n                controlID: 0x00C3,\n                productID: 0x405E,\n                serialNumber: \"45AFAFA6\"\n            ),\n            isPressed: false,\n            modifierFlags: []\n        ))\n\n        XCTAssertNotNil(result)\n    }\n\n    func testLogitechConfiguredProductIDMatchesEventWithoutSerialNumber() {\n        let transformer = ButtonActionsTransformer(mappings: [\n            .init(\n                button: .logitechControl(.init(controlID: 0x00C3, productID: 0x405E, serialNumber: nil)),\n                action: .arg0(.none)\n            )\n        ])\n\n        let result = transformer.findLogitechMapping(for: .init(\n            device: nil,\n            pid: nil,\n            display: nil,\n            mouseLocation: .zero,\n            controlIdentity: .init(controlID: 0x00C3, productID: 0x405E, serialNumber: nil),\n            isPressed: false,\n            modifierFlags: []\n        ))\n\n        XCTAssertNotNil(result)\n    }\n\n    // MARK: - Hold-while-pressed\n\n    func testHoldKeyPressDownOnButtonDownAndUpOnButtonUp() {\n        let simulator = RecordingKeySimulator()\n        let transformer = ButtonActionsTransformer(\n            mappings: [\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0001)),\n                    hold: true,\n                    action: .arg1(.keyPress([.a]))\n                )\n            ],\n            keySimulator: simulator\n        )\n\n        XCTAssertTrue(transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: true)))\n        XCTAssertTrue(transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: false)))\n\n        XCTAssertEqual(simulator.events, [.down([.a]), .up([.a]), .reset])\n    }\n\n    func testHoldIgnoresSecondPressEvenWithDifferentKeys() {\n        // If a duplicate pressed=true arrives that resolves to a different mapping (e.g. the\n        // event's modifier flags changed mid-hold), we must not overwrite the tracked keys —\n        // doing so would orphan the originally-pressed keys (release would only release the\n        // overwritten set, leaving the originals stuck).\n        let simulator = RecordingKeySimulator()\n        let transformer = ButtonActionsTransformer(\n            mappings: [\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0001)),\n                    hold: true,\n                    action: .arg1(.keyPress([.a]))\n                ),\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0001)),\n                    hold: true,\n                    shift: true,\n                    action: .arg1(.keyPress([.b]))\n                )\n            ],\n            keySimulator: simulator\n        )\n\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: true))\n        _ = transformer.handleLogitechControlEvent(\n            logitechContext(0x0001, pressed: true, modifierFlags: .maskShift)\n        )\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: false))\n\n        // Only the first mapping's keys are pressed and released; the second pressed event is\n        // ignored entirely so nothing gets stuck.\n        XCTAssertEqual(simulator.events, [.down([.a]), .up([.a]), .reset])\n    }\n\n    func testHoldDoesNotResendDownIfButtonRepeats() {\n        let simulator = RecordingKeySimulator()\n        let transformer = ButtonActionsTransformer(\n            mappings: [\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0001)),\n                    hold: true,\n                    action: .arg1(.keyPress([.a]))\n                )\n            ],\n            keySimulator: simulator\n        )\n\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: true))\n        // A second pressed=true event for the same button (e.g. a stuttering report) should not\n        // re-emit a key down — `pressAndStoreHeldKeys` short-circuits when the same keys are\n        // already tracked.\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: true))\n\n        XCTAssertEqual(simulator.events, [.down([.a])])\n    }\n\n    func testOverlappingHoldsDoNotResetWhileAnotherHoldIsActive() {\n        let simulator = RecordingKeySimulator()\n        let transformer = ButtonActionsTransformer(\n            mappings: [\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0001)),\n                    hold: true,\n                    action: .arg1(.keyPress([.command]))\n                ),\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0002)),\n                    hold: true,\n                    action: .arg1(.keyPress([.shift]))\n                )\n            ],\n            keySimulator: simulator\n        )\n\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: true))\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0002, pressed: true))\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0002, pressed: false))\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: false))\n\n        // Crucially: no `.reset` between releasing button 2 and releasing button 1, so the\n        // KeySimulator's tracked modifier flags still know command is held while shift is gone.\n        XCTAssertEqual(simulator.events, [\n            .down([.command]),\n            .down([.shift]),\n            .up([.shift]),\n            .up([.command]),\n            .reset\n        ])\n    }\n\n    func testHoldFallsBackToFallbackKeysWhenNothingTracked() {\n        // If a button-up arrives with no prior down (e.g. the down event was filtered out by\n        // app-specific matching), `releaseHeldKeys` still releases the action's keys so the\n        // synthetic key never gets stuck.\n        let simulator = RecordingKeySimulator()\n        let transformer = ButtonActionsTransformer(\n            mappings: [\n                .init(\n                    button: .logitechControl(.init(controlID: 0x0001)),\n                    hold: true,\n                    action: .arg1(.keyPress([.a]))\n                )\n            ],\n            keySimulator: simulator\n        )\n\n        _ = transformer.handleLogitechControlEvent(logitechContext(0x0001, pressed: false))\n\n        XCTAssertEqual(simulator.events, [.up([.a]), .reset])\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/EventTransformerManagerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class EventTransformerManagerTests: XCTestCase {\n    override func tearDown() {\n        super.tearDown()\n        ConfigurationState.shared.configuration = .init()\n    }\n\n    func testSyntheticSmoothedEventStillGetsModifierActions() throws {\n        let modifiers = Scheme.Scrolling.Modifiers(option: .changeSpeed(scale: 2))\n        ConfigurationState.shared.configuration = .init(schemes: [\n            Scheme(\n                scrolling: .init(\n                    reverse: .init(vertical: true),\n                    acceleration: .init(vertical: 2),\n                    smoothed: .init(vertical: .init(enabled: true, preset: .smooth)),\n                    modifiers: .init(vertical: modifiers)\n                )\n            )\n        ])\n\n        let event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .pixel,\n            wheelCount: 2,\n            wheel1: 0,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        let view = ScrollWheelEventView(event)\n        view.continuous = true\n        view.deltaYPt = 12\n        view.deltaYFixedPt = 12\n        event.flags = [.maskAlternate]\n        event.isLinearMouseSyntheticEvent = true\n\n        let transformer = EventTransformerManager.shared.get(\n            withCGEvent: event,\n            withSourcePid: nil,\n            withTargetPid: nil,\n            withMouseLocationPid: nil,\n            withDisplay: nil\n        )\n        let transformedEvent = try XCTUnwrap(transformer.transform(event))\n        let transformedView = ScrollWheelEventView(transformedEvent)\n\n        XCTAssertEqual(transformedView.deltaYPt, 24, accuracy: 0.001)\n        XCTAssertEqual(transformedView.deltaYFixedPt, 24, accuracy: 0.001)\n        XCTAssertEqual(transformedEvent.flags, [])\n    }\n\n    func testDisabledSmoothedConfigurationFallsBackToLegacyScrolling() throws {\n        ConfigurationState.shared.configuration = .init(schemes: [\n            Scheme(scrolling: .init(\n                smoothed: .init(vertical: .init(enabled: true, preset: .smooth))\n            )),\n            Scheme(scrolling: .init(\n                distance: .init(vertical: .line(3)),\n                smoothed: .init(vertical: .init(enabled: false))\n            ))\n        ])\n\n        let event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n\n        let transformer = EventTransformerManager.shared.get(\n            withCGEvent: event,\n            withSourcePid: nil,\n            withTargetPid: nil,\n            withMouseLocationPid: nil,\n            withDisplay: nil\n        )\n        let transformedEvent = try XCTUnwrap(transformer.transform(event))\n        let view = ScrollWheelEventView(transformedEvent)\n\n        XCTAssertEqual(view.deltaY, 3)\n        XCTAssertEqual(view.scrollPhase, nil)\n        XCTAssertEqual(view.momentumPhase, .none)\n    }\n\n    func testContinuousTrackpadEventStillGetsReverseScrollingWhenSmoothedExists() throws {\n        ConfigurationState.shared.configuration = .init(schemes: [\n            Scheme(\n                scrolling: .init(\n                    reverse: .init(vertical: true),\n                    smoothed: .init(vertical: .init(enabled: true, preset: .easeInOut))\n                )\n            )\n        ])\n\n        let event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .pixel,\n            wheelCount: 2,\n            wheel1: 0,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        let view = ScrollWheelEventView(event)\n        view.continuous = true\n        view.deltaYPt = 12\n        view.deltaYFixedPt = 12\n        view.scrollPhase = .began\n\n        let transformer = EventTransformerManager.shared.get(\n            withCGEvent: event,\n            withSourcePid: nil,\n            withTargetPid: nil,\n            withMouseLocationPid: nil,\n            withDisplay: nil\n        )\n        let transformedEvent = try XCTUnwrap(transformer.transform(event))\n        let transformedView = ScrollWheelEventView(transformedEvent)\n\n        XCTAssertEqual(transformedView.deltaYPt, 0, accuracy: 0.001)\n        XCTAssertLessThan(transformedView.deltaYFixedPt, 0)\n        XCTAssertGreaterThan(transformedView.deltaYFixedPt, -12)\n        XCTAssertEqual(transformedView.scrollPhase, .began)\n    }\n\n    func testButtonActionTransformerReceivesUniversalBackForwardSetting() throws {\n        ConfigurationState.shared.configuration = .init(schemes: [\n            Scheme(buttons: .init(\n                mappings: [.init(scroll: .left, action: .arg0(.mouseButtonBack))],\n                universalBackForward: .both\n            ))\n        ])\n\n        let event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 0,\n            wheel2: 1,\n            wheel3: 0\n        ))\n\n        let transformer = EventTransformerManager.shared.get(\n            withCGEvent: event,\n            withSourcePid: nil,\n            withTargetPid: nil,\n            withMouseLocationPid: nil,\n            withDisplay: nil\n        )\n        let buttonActionsTransformer = try XCTUnwrap((transformer as? [EventTransformer])?\n            .compactMap { $0 as? ButtonActionsTransformer }\n            .first)\n\n        XCTAssertEqual(buttonActionsTransformer.universalBackForward, .both)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/LinearScrollingTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class LinearScrollingTransformerTests: XCTestCase {\n    func testLinearScrollingByLines() throws {\n        let transformer = LinearScrollingVerticalTransformer(distance: .line(3))\n        var event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 42,\n            wheel2: 42,\n            wheel3: 0\n        ))\n        event = try XCTUnwrap(transformer.transform(event))\n        let view = ScrollWheelEventView(event)\n        XCTAssertFalse(view.continuous)\n        XCTAssertEqual(view.deltaX, 0)\n        XCTAssertEqual(view.deltaY, 3)\n    }\n\n    func testLinearScrollingByPixels() throws {\n        let transformer = LinearScrollingVerticalTransformer(distance: .pixel(36))\n        var event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 42,\n            wheel2: 42,\n            wheel3: 0\n        ))\n        event = try XCTUnwrap(transformer.transform(event))\n        let view = ScrollWheelEventView(event)\n        XCTAssertTrue(view.continuous)\n        XCTAssertEqual(view.deltaXPt, 0)\n        XCTAssertEqual(view.deltaYPt, 36)\n        XCTAssertEqual(view.deltaXFixedPt, 0)\n        XCTAssertEqual(view.deltaYFixedPt, 36)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/ModifierActionsTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class ModifierActionsTransformerTests: XCTestCase {\n    func testModifierActions() throws {\n        var event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 2,\n            wheel3: 0\n        ))\n        let modifiers = Scheme.Scrolling.Modifiers(\n            command: .auto,\n            shift: .alterOrientation,\n            option: .changeSpeed(scale: 2),\n            control: .changeSpeed(scale: 3)\n        )\n        let transformer = ModifierActionsTransformer(modifiers: .init(vertical: modifiers, horizontal: modifiers))\n        event.flags.insert(.maskCommand)\n        event.flags.insert(.maskShift)\n        event.flags.insert(.maskAlternate)\n        event.flags.insert(.maskControl)\n        event = try XCTUnwrap(transformer.transform(event))\n        var view = ScrollWheelEventView(event)\n        XCTAssertEqual(view.deltaX, 6)\n        XCTAssertEqual(view.deltaY, 12)\n\n        event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 2,\n            wheel3: 0\n        ))\n        event.flags.insert(.maskCommand)\n        event.flags.insert(.maskShift)\n        event.flags.insert(.maskAlternate)\n        event = try XCTUnwrap(transformer.transform(event))\n        view = ScrollWheelEventView(event)\n        XCTAssertEqual(view.deltaX, 2)\n        XCTAssertEqual(view.deltaY, 4)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/ReverseScrollingTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class ReverseScrollingTransformerTests: XCTestCase {\n    func testReverseScrollingVertically() throws {\n        let transformer = ReverseScrollingTransformer(vertically: true)\n        var event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 2,\n            wheel3: 0\n        ))\n        event = try XCTUnwrap(transformer.transform(event))\n        let view = ScrollWheelEventView(event)\n        XCTAssertEqual(view.deltaX, 2)\n        XCTAssertEqual(view.deltaY, -1)\n    }\n\n    func testReverseScrollingHorizontally() throws {\n        let transformer = ReverseScrollingTransformer(horizontally: true)\n        var event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 2,\n            wheel3: 0\n        ))\n        event = try XCTUnwrap(transformer.transform(event))\n        let view = ScrollWheelEventView(event)\n        XCTAssertEqual(view.deltaX, -2)\n        XCTAssertEqual(view.deltaY, 1)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/SmoothedScrollingEngineTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class SmoothedScrollingEngineTests: XCTestCase {\n    func testSmoothedScrollingTransitionsIntoMomentumAndEnds() {\n        let engine = SmoothedScrollingEngine(\n            smoothed: .init(\n                vertical: .init(\n                    enabled: true,\n                    preset: .smooth,\n                    response: Decimal(string: \"0.45\"),\n                    speed: 1,\n                    acceleration: Decimal(string: \"1.2\"),\n                    inertia: Decimal(string: \"0.65\")\n                )\n            )\n        )\n\n        var emissions: [SmoothedScrollingEngine.Emission] = []\n\n        for step in 0 ..< 6 {\n            let timestamp = Double(step) / 120\n            engine.feed(deltaX: 0, deltaY: 40, timestamp: timestamp)\n            if let emission = engine.advance(to: timestamp + 1.0 / 120) {\n                emissions.append(emission)\n            }\n        }\n\n        for step in 6 ..< 240 {\n            let timestamp = Double(step + 1) / 120\n            if let emission = engine.advance(to: timestamp) {\n                emissions.append(emission)\n            }\n        }\n\n        XCTAssertEqual(emissions.first?.phase, .touchBegan)\n        XCTAssertTrue(emissions.dropFirst().contains { $0.phase == .touchChanged })\n        let endedIndex = emissions.firstIndex { $0.phase == .touchEnded }\n        let momentumBeginIndex = emissions.firstIndex { $0.phase == .momentumBegan }\n        XCTAssertNotNil(endedIndex)\n        XCTAssertNotNil(momentumBeginIndex)\n        if let endedIndex, let momentumBeginIndex {\n            XCTAssertLessThan(endedIndex, momentumBeginIndex)\n        }\n        XCTAssertTrue(emissions.contains { $0.phase == .momentumBegan })\n        XCTAssertTrue(emissions.contains { $0.phase == .momentumChanged })\n        XCTAssertEqual(emissions.last?.phase, .momentumEnded)\n    }\n\n    func testSmoothedScrollingPreservesPassthroughAxis() {\n        let engine = SmoothedScrollingEngine(\n            smoothed: .init(\n                vertical: .init(\n                    enabled: true,\n                    preset: .smooth,\n                    response: Decimal(string: \"0.45\"),\n                    speed: 1,\n                    acceleration: Decimal(string: \"1.2\"),\n                    inertia: Decimal(string: \"0.65\")\n                )\n            )\n        )\n\n        engine.feed(deltaX: 18, deltaY: 24, timestamp: 0)\n        let emission = engine.advance(to: 1.0 / 120)\n\n        XCTAssertEqual(emission?.phase, .touchBegan)\n        XCTAssertEqual(emission?.deltaX ?? 0, 18, accuracy: 0.001)\n        XCTAssertGreaterThan(abs(emission?.deltaY ?? 0), 0)\n    }\n\n    func testEaseInStartsSlowerThanEaseOut() {\n        let easeInEngine = SmoothedScrollingEngine(smoothed: .init(\n            vertical: Scheme.Scrolling.Smoothed.Preset.easeIn.defaultConfiguration\n        ))\n        let easeOutEngine = SmoothedScrollingEngine(smoothed: .init(\n            vertical: Scheme.Scrolling.Smoothed.Preset.easeOut.defaultConfiguration\n        ))\n\n        easeInEngine.feed(deltaX: 0, deltaY: 36, timestamp: 0)\n        easeOutEngine.feed(deltaX: 0, deltaY: 36, timestamp: 0)\n\n        let easeInEmission = easeInEngine.advance(to: 1.0 / 120)\n        let easeOutEmission = easeOutEngine.advance(to: 1.0 / 120)\n\n        XCTAssertNotNil(easeInEmission)\n        XCTAssertNotNil(easeOutEmission)\n        XCTAssertLessThan(abs(easeInEmission?.deltaY ?? 0), abs(easeOutEmission?.deltaY ?? 0))\n    }\n\n    func testMomentumReengagementBlendsAdditionalInputWithoutSharpJump() throws {\n        let engine = SmoothedScrollingEngine(smoothed: .init(\n            vertical: Scheme.Scrolling.Smoothed.Preset.easeInOut.defaultConfiguration\n        ))\n\n        var latestMomentumEmission: SmoothedScrollingEngine.Emission?\n\n        for step in 0 ..< 6 {\n            let timestamp = Double(step) / 120\n            engine.feed(deltaX: 0, deltaY: 40, timestamp: timestamp)\n            _ = engine.advance(to: timestamp + 1.0 / 120)\n        }\n\n        for step in 6 ..< 24 {\n            let timestamp = Double(step + 1) / 120\n            if let emission = engine.advance(to: timestamp), emission.phase == .momentumChanged {\n                latestMomentumEmission = emission\n            }\n        }\n\n        let baseline = try XCTUnwrap(latestMomentumEmission)\n        let reengagementTimestamp = 25.0 / 120.0\n        engine.feed(deltaX: 0, deltaY: 36, timestamp: reengagementTimestamp)\n        let reengagedEmission = try XCTUnwrap(engine.advance(to: reengagementTimestamp + 1.0 / 120.0))\n\n        XCTAssertEqual(reengagedEmission.phase, .touchBegan)\n        XCTAssertGreaterThan(abs(reengagedEmission.deltaY), abs(baseline.deltaY))\n        XCTAssertLessThan(abs(reengagedEmission.deltaY), abs(baseline.deltaY) * 2.6)\n    }\n\n    func testMomentumTailReengagementRecoversTowardFreshPickup() throws {\n        let configuration = Scheme.Scrolling.Smoothed.Preset.easeInOut.defaultConfiguration\n        let engine = SmoothedScrollingEngine(smoothed: .init(vertical: configuration))\n        let freshEngine = SmoothedScrollingEngine(smoothed: .init(vertical: configuration))\n\n        var tailEmission: SmoothedScrollingEngine.Emission?\n\n        for step in 0 ..< 6 {\n            let timestamp = Double(step) / 120\n            engine.feed(deltaX: 0, deltaY: 40, timestamp: timestamp)\n            _ = engine.advance(to: timestamp + 1.0 / 120)\n        }\n\n        for step in 6 ..< 240 {\n            let timestamp = Double(step + 1) / 120\n            if let emission = engine.advance(to: timestamp),\n               emission.phase == .momentumChanged,\n               abs(emission.deltaY) < 0.25 {\n                tailEmission = emission\n                break\n            }\n        }\n\n        let baselineTail = try XCTUnwrap(tailEmission)\n\n        freshEngine.feed(deltaX: 0, deltaY: 36, timestamp: 0)\n        let freshPickup = try XCTUnwrap(freshEngine.advance(to: 1.0 / 120))\n\n        let reengagementTimestamp = 2.0\n        engine.feed(deltaX: 0, deltaY: 36, timestamp: reengagementTimestamp)\n        let reengagedEmission = try XCTUnwrap(engine.advance(to: reengagementTimestamp + 1.0 / 120.0))\n\n        XCTAssertEqual(reengagedEmission.phase, .touchBegan)\n        XCTAssertGreaterThan(abs(reengagedEmission.deltaY), abs(baselineTail.deltaY) * 3)\n        XCTAssertGreaterThan(abs(reengagedEmission.deltaY), abs(freshPickup.deltaY) * 0.7)\n    }\n\n    func testExclusiveAxisSwitchResetsPreviousAxisMomentum() throws {\n        let configuration = Scheme.Scrolling.Smoothed.Preset.easeInOut.defaultConfiguration\n        let engine = SmoothedScrollingEngine(smoothed: .init(\n            vertical: configuration,\n            horizontal: configuration\n        ))\n\n        for step in 0 ..< 6 {\n            let timestamp = Double(step) / 120\n            engine.feed(deltaX: 0, deltaY: 40, timestamp: timestamp)\n            _ = engine.advance(to: timestamp + 1.0 / 120)\n        }\n\n        var verticalMomentumDetected = false\n        for step in 6 ..< 60 {\n            let timestamp = Double(step + 1) / 120\n            if let emission = engine.advance(to: timestamp), emission.phase == .momentumChanged,\n               abs(emission.deltaY) > 0.01 {\n                verticalMomentumDetected = true\n                break\n            }\n        }\n        XCTAssertTrue(verticalMomentumDetected)\n\n        let switchTimestamp = 1.0\n        engine.resetOtherAxis(ifExclusiveIncomingAxis: .horizontal)\n        engine.feed(deltaX: 36, deltaY: 0, timestamp: switchTimestamp)\n        let switchedEmission = try XCTUnwrap(engine.advance(to: switchTimestamp + 1.0 / 120.0))\n\n        XCTAssertEqual(switchedEmission.phase, .touchBegan)\n        XCTAssertGreaterThan(abs(switchedEmission.deltaX), 0.01)\n        XCTAssertEqual(switchedEmission.deltaY, 0, accuracy: 0.001)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/SmoothedScrollingTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class SmoothedScrollingTransformerTests: XCTestCase {\n    func testModifierAlterOrientationAppliesBeforeDiscreteSmoothedScrolling() throws {\n        var emittedEvents: [CGEvent] = []\n        var now = 0.0\n        let modifiers = Scheme.Scrolling.Modifiers(shift: .alterOrientation)\n        let smoothedTransformer = SmoothedScrollingTransformer(\n            smoothed: .init(vertical: Scheme.Scrolling.Smoothed.Preset.smooth.defaultConfiguration),\n            now: { now },\n            eventSink: { emittedEvents.append($0.copy() ?? $0) }\n        )\n        let transformer: [EventTransformer] = [\n            ModifierActionsTransformer(modifiers: .init(vertical: modifiers, horizontal: modifiers)),\n            smoothedTransformer\n        ]\n\n        let originalEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        originalEvent.flags = [.maskShift]\n\n        let transformedEvent = try XCTUnwrap(transformer.transform(originalEvent))\n        let transformedView = ScrollWheelEventView(transformedEvent)\n        XCTAssertEqual(transformedView.deltaX, 1)\n        XCTAssertEqual(transformedView.deltaY, 0)\n        XCTAssertEqual(transformedEvent.flags, [])\n\n        now = 1.0 / 120.0\n        smoothedTransformer.tick()\n        XCTAssertTrue(emittedEvents.isEmpty)\n    }\n\n    func testModifierChangeSpeedAppliesBeforeDiscreteSmoothedScrolling() throws {\n        var baselineEmittedEvents: [CGEvent] = []\n        var scaledEmittedEvents: [CGEvent] = []\n        var now = 0.0\n        let modifiers = Scheme.Scrolling.Modifiers(option: .changeSpeed(scale: 2))\n\n        let baselineTransformer = SmoothedScrollingTransformer(\n            smoothed: .init(vertical: Scheme.Scrolling.Smoothed.Preset.smooth.defaultConfiguration),\n            now: { now },\n            eventSink: { baselineEmittedEvents.append($0.copy() ?? $0) }\n        )\n        let scaledTransformer = SmoothedScrollingTransformer(\n            smoothed: .init(vertical: Scheme.Scrolling.Smoothed.Preset.smooth.defaultConfiguration),\n            now: { now },\n            eventSink: { scaledEmittedEvents.append($0.copy() ?? $0) }\n        )\n\n        let baselineChain: [EventTransformer] = [\n            ModifierActionsTransformer(modifiers: .init(vertical: modifiers, horizontal: modifiers)),\n            baselineTransformer\n        ]\n        let scaledChain: [EventTransformer] = [\n            ModifierActionsTransformer(modifiers: .init(vertical: modifiers, horizontal: modifiers)),\n            scaledTransformer\n        ]\n\n        let baselineEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        let scaledEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        scaledEvent.flags = [.maskAlternate]\n\n        XCTAssertNil(baselineChain.transform(baselineEvent))\n        XCTAssertNil(scaledChain.transform(scaledEvent))\n\n        now = 1.0 / 120.0\n        baselineTransformer.tick()\n        scaledTransformer.tick()\n\n        let baselineView = try ScrollWheelEventView(XCTUnwrap(baselineEmittedEvents.first))\n        let scaledView = try ScrollWheelEventView(XCTUnwrap(scaledEmittedEvents.first))\n        XCTAssertGreaterThan(abs(scaledView.deltaYPt), abs(baselineView.deltaYPt))\n    }\n\n    func testShiftOrientationSwitchClearsPreviousAxisMomentum() throws {\n        var emittedEvents: [CGEvent] = []\n        var now = 0.0\n        let modifiers = Scheme.Scrolling.Modifiers(shift: .alterOrientation)\n        let smoothedTransformer = SmoothedScrollingTransformer(\n            smoothed: .init(\n                vertical: Scheme.Scrolling.Smoothed.Preset.easeInOut.defaultConfiguration,\n                horizontal: Scheme.Scrolling.Smoothed.Preset.easeInOut.defaultConfiguration\n            ),\n            now: { now },\n            eventSink: { emittedEvents.append($0.copy() ?? $0) }\n        )\n        let transformer: [EventTransformer] = [\n            ModifierActionsTransformer(modifiers: .init(vertical: modifiers, horizontal: modifiers)),\n            smoothedTransformer\n        ]\n\n        for step in 0 ..< 6 {\n            let event = try XCTUnwrap(CGEvent(\n                scrollWheelEvent2Source: nil,\n                units: .line,\n                wheelCount: 2,\n                wheel1: 1,\n                wheel2: 0,\n                wheel3: 0\n            ))\n            now = Double(step) / 120\n            XCTAssertNil(transformer.transform(event))\n            now += 1.0 / 120.0\n            smoothedTransformer.tick()\n        }\n\n        var sawVerticalMomentum = false\n        for _ in 0 ..< 30 {\n            now += 1.0 / 120.0\n            smoothedTransformer.tick()\n            if let view = emittedEvents.last.map(ScrollWheelEventView.init), abs(view.deltaYPt) > 0.01 {\n                sawVerticalMomentum = true\n            }\n        }\n        XCTAssertTrue(sawVerticalMomentum)\n\n        let shiftedEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        shiftedEvent.flags = [.maskShift]\n        XCTAssertNil(transformer.transform(shiftedEvent))\n\n        now += 1.0 / 120.0\n        smoothedTransformer.tick()\n\n        let switchedView = try ScrollWheelEventView(XCTUnwrap(emittedEvents.last))\n        XCTAssertGreaterThan(abs(switchedView.deltaXPt), 0.01)\n        XCTAssertEqual(switchedView.deltaYPt, 0, accuracy: 0.001)\n    }\n\n    func testSmoothedScrollingPreservesUnsmoothedAxisAndEmitsSyntheticEvent() throws {\n        var emittedEvents: [CGEvent] = []\n        var now = 0.0\n        let transformer = SmoothedScrollingTransformer(\n            smoothed: .init(\n                vertical: .init(\n                    enabled: true,\n                    preset: .smooth,\n                    response: Decimal(string: \"0.45\"),\n                    speed: 1,\n                    acceleration: Decimal(string: \"1.2\"),\n                    inertia: Decimal(string: \"0.65\")\n                )\n            ),\n            now: { now },\n            eventSink: { emittedEvents.append($0.copy() ?? $0) }\n        )\n\n        let originalEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 2,\n            wheel2: 3,\n            wheel3: 0\n        ))\n        originalEvent.flags = [.maskAlternate]\n\n        let passthroughEvent = try XCTUnwrap(transformer.transform(originalEvent))\n        let passthroughView = ScrollWheelEventView(passthroughEvent)\n        XCTAssertEqual(passthroughView.deltaX, 3)\n        XCTAssertEqual(passthroughView.deltaY, 0)\n\n        now = 1.0 / 120.0\n        transformer.tick()\n\n        let emittedEvent = try XCTUnwrap(emittedEvents.first)\n        let emittedView = ScrollWheelEventView(emittedEvent)\n        XCTAssertTrue(emittedEvent.isLinearMouseSyntheticEvent)\n        XCTAssertEqual(emittedView.deltaX, 0)\n        XCTAssertEqual(emittedView.scrollPhase, .began)\n        XCTAssertEqual(emittedView.momentumPhase, .none)\n        XCTAssertGreaterThan(abs(emittedView.deltaYPt), 0)\n        XCTAssertEqual(emittedEvent.flags, [.maskAlternate])\n    }\n\n    func testDiscreteWheelInputUsesLineDeltaForStartupEvenWhenPointDeltaExists() throws {\n        var emittedEvents: [CGEvent] = []\n        var now = 0.0\n        let transformer = SmoothedScrollingTransformer(\n            smoothed: .init(\n                vertical: Scheme.Scrolling.Smoothed.Preset.smooth.defaultConfiguration\n            ),\n            now: { now },\n            eventSink: { emittedEvents.append($0.copy() ?? $0) }\n        )\n\n        let originalEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        let originalView = ScrollWheelEventView(originalEvent)\n        originalView.deltaYPt = 1\n        originalView.deltaYFixedPt = 0.1\n        XCTAssertFalse(originalView.continuous)\n\n        XCTAssertNil(transformer.transform(originalEvent))\n\n        now = 1.0 / 120.0\n        transformer.tick()\n\n        let emittedEvent = try XCTUnwrap(emittedEvents.first)\n        let emittedView = ScrollWheelEventView(emittedEvent)\n        XCTAssertGreaterThan(abs(emittedView.deltaYPt), 3)\n        XCTAssertEqual(emittedView.scrollPhase, .began)\n    }\n\n    func testContinuousTrackpadInputWithNativePhaseIsSmoothedInPlace() throws {\n        var now = 0.0\n        let transformer = SmoothedScrollingTransformer(\n            smoothed: .init(\n                vertical: Scheme.Scrolling.Smoothed.Preset.easeInOut.defaultConfiguration\n            )\n        ) {\n            now\n        }\n\n        let originalEvent = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .pixel,\n            wheelCount: 2,\n            wheel1: 0,\n            wheel2: 0,\n            wheel3: 0\n        ))\n        let originalView = ScrollWheelEventView(originalEvent)\n        originalView.continuous = true\n        originalView.deltaYPt = 9\n        originalView.deltaYFixedPt = 9\n        originalView.scrollPhase = .began\n\n        let transformedEvent = try XCTUnwrap(transformer.transform(originalEvent))\n        let transformedView = ScrollWheelEventView(transformedEvent)\n        XCTAssertEqual(transformedView.deltaYPt, 0, accuracy: 0.001)\n        XCTAssertGreaterThan(transformedView.deltaYFixedPt, 0)\n        XCTAssertLessThan(transformedView.deltaYFixedPt, 9)\n        XCTAssertEqual(transformedView.scrollPhase, .began)\n    }\n\n    func testExtendedSpeedRangeProducesMuchStrongerInitialEmission() throws {\n        let baseline = try firstDiscreteEmission(\n            configuration: .init(\n                enabled: true,\n                preset: .easeInOut,\n                response: Decimal(string: \"0.68\"),\n                speed: Decimal(string: \"3.0\"),\n                acceleration: Decimal(string: \"1.10\"),\n                inertia: Decimal(string: \"0.74\")\n            )\n        )\n        let boosted = try firstDiscreteEmission(\n            configuration: .init(\n                enabled: true,\n                preset: .easeInOut,\n                response: Decimal(string: \"0.68\"),\n                speed: Decimal(string: \"8.0\"),\n                acceleration: Decimal(string: \"1.10\"),\n                inertia: Decimal(string: \"0.74\")\n            )\n        )\n\n        XCTAssertGreaterThan(abs(boosted.deltaYPt), abs(baseline.deltaYPt) * 1.8)\n    }\n\n    func testExtendedResponseRangeProducesMuchQuickerPickup() throws {\n        let baseline = try firstDiscreteEmission(\n            configuration: .init(\n                enabled: true,\n                preset: .easeInOut,\n                response: Decimal(string: \"1.0\"),\n                speed: Decimal(string: \"1.00\"),\n                acceleration: Decimal(string: \"1.10\"),\n                inertia: Decimal(string: \"0.74\")\n            )\n        )\n        let extended = try firstDiscreteEmission(\n            configuration: .init(\n                enabled: true,\n                preset: .easeInOut,\n                response: Decimal(string: \"2.0\"),\n                speed: Decimal(string: \"1.00\"),\n                acceleration: Decimal(string: \"1.10\"),\n                inertia: Decimal(string: \"0.74\")\n            )\n        )\n\n        XCTAssertGreaterThan(abs(extended.deltaYPt), abs(baseline.deltaYPt) * 1.25)\n    }\n\n    private func firstDiscreteEmission(\n        configuration: Scheme.Scrolling.Smoothed\n    ) throws -> ScrollWheelEventView {\n        var emittedEvents: [CGEvent] = []\n        var now = 0.0\n        let transformer = SmoothedScrollingTransformer(\n            smoothed: .init(vertical: configuration),\n            now: { now },\n            eventSink: { emittedEvents.append($0.copy() ?? $0) }\n        )\n\n        let event = try XCTUnwrap(CGEvent(\n            scrollWheelEvent2Source: nil,\n            units: .line,\n            wheelCount: 2,\n            wheel1: 1,\n            wheel2: 0,\n            wheel3: 0\n        ))\n\n        XCTAssertNil(transformer.transform(event))\n\n        now = 1.0 / 120.0\n        transformer.tick()\n\n        return try ScrollWheelEventView(XCTUnwrap(emittedEvents.first))\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/EventTransformer/UniversalBackForwardTransformerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class UniversalBackForwardTransformerTests: XCTestCase {\n    func testReplacementUsesSwipeForBackInSupportedApp() {\n        XCTAssertEqual(\n            UniversalBackForwardTransformer.replacement(\n                for: .back,\n                universalBackForward: .both,\n                targetBundleIdentifier: \"com.apple.Safari\"\n            ),\n            .navigationSwipe(.left)\n        )\n    }\n\n    func testReplacementUsesSwipeForForwardInSupportedApp() {\n        XCTAssertEqual(\n            UniversalBackForwardTransformer.replacement(\n                for: .forward,\n                universalBackForward: .both,\n                targetBundleIdentifier: \"com.binarynights.ForkLift\"\n            ),\n            .navigationSwipe(.right)\n        )\n    }\n\n    func testReplacementFallsBackToMouseButtonWhenUniversalBackForwardDisabled() {\n        XCTAssertEqual(\n            UniversalBackForwardTransformer.replacement(\n                for: .back,\n                universalBackForward: .none,\n                targetBundleIdentifier: \"com.apple.Safari\"\n            ),\n            .mouseButton(.back)\n        )\n    }\n\n    func testReplacementFallsBackToMouseButtonWhenDirectionIsNotEnabled() {\n        XCTAssertEqual(\n            UniversalBackForwardTransformer.replacement(\n                for: .forward,\n                universalBackForward: .backOnly,\n                targetBundleIdentifier: \"com.apple.Safari\"\n            ),\n            .mouseButton(.forward)\n        )\n    }\n\n    func testReplacementFallsBackToMouseButtonInUnsupportedApp() {\n        XCTAssertEqual(\n            UniversalBackForwardTransformer.replacement(\n                for: .back,\n                universalBackForward: .both,\n                targetBundleIdentifier: \"com.example.CustomBrowser\"\n            ),\n            .mouseButton(.back)\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Model/ConfigurationTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class ConfigurationTests: XCTestCase {\n    func testDump() throws {\n        try print(Configuration(schemes: []).dump())\n    }\n\n    func testMergeScheme() {\n        var scheme = Scheme()\n\n        XCTAssertNil(scheme.$scrolling)\n\n        Scheme(scrolling: .init(reverse: .init(vertical: true))).merge(into: &scheme)\n\n        XCTAssertEqual(scheme.scrolling.reverse.vertical, true)\n        XCTAssertNil(scheme.scrolling.reverse.horizontal)\n\n        Scheme(scrolling: .init(reverse: .init(vertical: false, horizontal: true))).merge(into: &scheme)\n\n        XCTAssertEqual(scheme.scrolling.reverse.vertical, false)\n        XCTAssertEqual(scheme.scrolling.reverse.horizontal, true)\n\n        Scheme(scrolling: .init(reverse: .init(vertical: true))).merge(into: &scheme)\n\n        XCTAssertEqual(scheme.scrolling.reverse.vertical, true)\n        XCTAssertEqual(scheme.scrolling.reverse.horizontal, true)\n    }\n\n    func testMergeAutoScroll() {\n        var scheme = Scheme()\n        scheme.buttons.autoScroll.enabled = true\n        scheme.buttons.autoScroll.modes = [.hold]\n\n        var trigger = Scheme.Buttons.Mapping()\n        trigger.button = .mouse(4)\n        trigger.shift = true\n        scheme.buttons.autoScroll.trigger = trigger\n\n        Scheme().merge(into: &scheme)\n\n        XCTAssertEqual(scheme.buttons.autoScroll.enabled, true)\n        XCTAssertEqual(scheme.buttons.autoScroll.modes, [.hold])\n        XCTAssertEqual(scheme.buttons.autoScroll.trigger?.button, .mouse(4))\n        XCTAssertEqual(scheme.buttons.autoScroll.trigger?.modifierFlags.contains(.maskShift), true)\n    }\n\n    func testMergeAutoScrollPreservesInheritedFields() {\n        var scheme = Scheme()\n        scheme.buttons.autoScroll.enabled = true\n        scheme.buttons.autoScroll.modes = [.toggle]\n        scheme.buttons.autoScroll.speed = 1\n\n        var trigger = Scheme.Buttons.Mapping()\n        trigger.button = .mouse(2)\n        trigger.command = true\n        scheme.buttons.autoScroll.trigger = trigger\n\n        var override = Scheme()\n        override.buttons.autoScroll.speed = 2\n        override.buttons.autoScroll.modes = [.toggle, .hold]\n        override.merge(into: &scheme)\n\n        XCTAssertEqual(scheme.buttons.autoScroll.enabled, true)\n        XCTAssertEqual(scheme.buttons.autoScroll.modes, [.toggle, .hold])\n        XCTAssertEqual(scheme.buttons.autoScroll.speed, 2)\n        XCTAssertEqual(scheme.buttons.autoScroll.trigger?.button, .mouse(2))\n        XCTAssertEqual(scheme.buttons.autoScroll.trigger?.modifierFlags.contains(.maskCommand), true)\n    }\n\n    func testMergeAutoScrollAllowsDisablingInheritedSetting() {\n        var scheme = Scheme()\n        scheme.buttons.autoScroll.enabled = true\n        scheme.buttons.autoScroll.modes = [.toggle]\n\n        var override = Scheme()\n        override.buttons.autoScroll.enabled = false\n        override.merge(into: &scheme)\n\n        XCTAssertEqual(scheme.buttons.autoScroll.enabled, false)\n        XCTAssertEqual(scheme.buttons.autoScroll.modes, [.toggle])\n    }\n\n    func testMappingDecodesLegacyGenericModifierFlagsWithoutRawFlags() throws {\n        let mapping = try JSONDecoder().decode(\n            Scheme.Buttons.Mapping.self,\n            from: XCTUnwrap(#\"{\"button\":3,\"command\":true}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(mapping.modifierFlags, [.maskCommand])\n        XCTAssertTrue(mapping.command == true)\n        XCTAssertFalse(mapping.shift == true)\n    }\n\n    func testMappingDecodesLegacyLogitechControlFieldIntoButton() throws {\n        let mapping = try JSONDecoder().decode(\n            Scheme.Buttons.Mapping.self,\n            from: XCTUnwrap(\n                #\"{\"logiButton\":{\"controlID\":208,\"logicalDeviceProductID\":16478,\"logicalDeviceSerialNumber\":\"ABC123\"}}\"#\n                    .data(using: .utf8)\n            )\n        )\n\n        XCTAssertEqual(\n            mapping.button,\n            .logitechControl(.init(controlID: 208, productID: 16_478, serialNumber: \"ABC123\"))\n        )\n    }\n\n    func testMappingEncodesLogitechControlButtonAsTaggedStructure() throws {\n        let mapping = Scheme.Buttons.Mapping(\n            button: .logitechControl(.init(controlID: 208, productID: 16_478, serialNumber: \"ABC123\"))\n        )\n\n        let data = try JSONEncoder().encode(mapping)\n        let jsonObject = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any])\n        let button = try XCTUnwrap(jsonObject[\"button\"] as? [String: Any])\n\n        XCTAssertEqual(button[\"kind\"] as? String, \"logitechControl\")\n        XCTAssertEqual(button[\"controlID\"] as? Int, 208)\n        XCTAssertEqual(button[\"productID\"] as? Int, 16_478)\n        XCTAssertEqual(button[\"serialNumber\"] as? String, \"ABC123\")\n    }\n\n    func testMappingDecodesHoldFlag() throws {\n        let mapping = try JSONDecoder().decode(\n            Scheme.Buttons.Mapping.self,\n            from: XCTUnwrap(#\"{\"button\":3,\"hold\":true,\"action\":{\"keyPress\":[\"c\"]}}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(mapping.button, .mouse(3))\n        XCTAssertEqual(mapping.hold, true)\n        XCTAssertNil(mapping.repeat)\n    }\n\n    func testMappingEncodesHoldFlag() throws {\n        let mapping = Scheme.Buttons.Mapping(\n            button: .mouse(3),\n            hold: true,\n            action: .arg1(.keyPress([.c]))\n        )\n\n        let data = try JSONEncoder().encode(mapping)\n        let jsonObject = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any])\n\n        XCTAssertEqual(jsonObject[\"button\"] as? Int, 3)\n        XCTAssertEqual(jsonObject[\"hold\"] as? Bool, true)\n        XCTAssertNil(jsonObject[\"repeat\"])\n    }\n\n    func testKeyPressBehaviorMapsFlagsExclusively() {\n        var mapping = Scheme.Buttons.Mapping()\n\n        mapping.keyPressBehavior = .repeat\n        XCTAssertEqual(mapping.repeat, true)\n        XCTAssertNil(mapping.hold)\n\n        mapping.keyPressBehavior = .holdWhilePressed\n        XCTAssertEqual(mapping.hold, true)\n        XCTAssertNil(mapping.repeat)\n\n        mapping.keyPressBehavior = .sendOnRelease\n        XCTAssertNil(mapping.hold)\n        XCTAssertNil(mapping.repeat)\n    }\n\n    func testLogitechControlButtonDecodesHexProductID() throws {\n        let mapping = try JSONDecoder().decode(\n            Scheme.Buttons.Mapping.self,\n            from: XCTUnwrap(\n                #\"{\"button\":{\"kind\":\"logitechControl\",\"controlID\":208,\"productID\":\"0x405E\"}}\"#\n                    .data(using: .utf8)\n            )\n        )\n\n        XCTAssertEqual(\n            mapping.button,\n            .logitechControl(.init(controlID: 208, productID: 0x405E, serialNumber: nil))\n        )\n    }\n\n    func testDecodeAutoScrollSingleMode() throws {\n        let autoScroll = try JSONDecoder().decode(\n            Scheme.Buttons.AutoScroll.self,\n            from: XCTUnwrap(#\"{\"enabled\":true,\"mode\":\"hold\"}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(autoScroll.modes, [.hold])\n        XCTAssertEqual(autoScroll.normalizedModes, [.hold])\n    }\n\n    func testDecodeAutoScrollMultipleModes() throws {\n        let autoScroll = try JSONDecoder().decode(\n            Scheme.Buttons.AutoScroll.self,\n            from: XCTUnwrap(#\"{\"enabled\":true,\"mode\":[\"toggle\",\"hold\"]}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(autoScroll.modes, [.toggle, .hold])\n        XCTAssertEqual(autoScroll.normalizedModes, [.toggle, .hold])\n    }\n\n    func testMergeSmoothedScrollingPreservesInheritedFields() {\n        var scheme = Scheme(\n            scrolling: .init(\n                smoothed: .init(\n                    vertical: .init(\n                        preset: .smooth,\n                        response: Decimal(string: \"0.45\"),\n                        speed: 1,\n                        acceleration: Decimal(string: \"1.2\"),\n                        inertia: Decimal(string: \"0.65\")\n                    )\n                )\n            )\n        )\n\n        Scheme(\n            scrolling: .init(\n                smoothed: .init(\n                    vertical: .init(\n                        preset: .smooth,\n                        inertia: 8\n                    )\n                )\n            )\n        ).merge(into: &scheme)\n\n        XCTAssertEqual(scheme.scrolling.smoothed.vertical?.preset, .smooth)\n        XCTAssertEqual(scheme.scrolling.smoothed.vertical?.response, Decimal(string: \"0.45\"))\n        XCTAssertEqual(scheme.scrolling.smoothed.vertical?.speed, 1)\n        XCTAssertEqual(scheme.scrolling.smoothed.vertical?.acceleration, Decimal(string: \"1.2\"))\n        XCTAssertEqual(scheme.scrolling.smoothed.vertical?.inertia, 8)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Model/Scheme/Buttons/GestureTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class GestureTests: XCTestCase {\n    // MARK: - Legacy \"button\" → \"trigger\" migration\n\n    func testDecodeLegacyButtonField() throws {\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(#\"{\"button\":2,\"threshold\":60}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(gesture.trigger?.button, .mouse(2))\n        XCTAssertEqual(gesture.threshold, 60)\n    }\n\n    func testDecodeLegacyButtonFieldWithEnabledTrue() throws {\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(#\"{\"enabled\":true,\"button\":2}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(gesture.trigger?.button, .mouse(2))\n    }\n\n    func testDecodeLegacyButtonFieldWithEnabledFalse() throws {\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(#\"{\"enabled\":false,\"button\":2}\"#.data(using: .utf8))\n        )\n\n        XCTAssertEqual(gesture.enabled, false)\n        XCTAssertEqual(gesture.trigger?.button, .mouse(2), \"button should still migrate even when disabled\")\n    }\n\n    func testDecodeLegacyEnabledFalseWithTrigger() throws {\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(\n                #\"{\"enabled\":false,\"trigger\":{\"button\":2}}\"#.data(using: .utf8)\n            )\n        )\n\n        XCTAssertEqual(gesture.enabled, false)\n        XCTAssertNotNil(gesture.trigger, \"trigger should be preserved even when disabled\")\n    }\n\n    func testDecodeTriggerTakesPriorityOverLegacyButton() throws {\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(\n                #\"{\"button\":3,\"trigger\":{\"button\":4}}\"#.data(using: .utf8)\n            )\n        )\n\n        XCTAssertEqual(gesture.trigger?.button, .mouse(4), \"trigger should take priority over legacy button\")\n    }\n\n    func testDecodeNeitherButtonNorTrigger() throws {\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(#\"{\"threshold\":80}\"#.data(using: .utf8))\n        )\n\n        XCTAssertNil(gesture.trigger)\n        XCTAssertEqual(gesture.threshold, 80)\n    }\n\n    // MARK: - Encoding\n\n    func testEncodeWritesEnabledButNotLegacyButton() throws {\n        var gesture = Scheme.Buttons.Gesture()\n        gesture.enabled = true\n        var mapping = Scheme.Buttons.Mapping()\n        mapping.button = .mouse(2)\n        gesture.trigger = mapping\n        gesture.threshold = 50\n\n        let data = try JSONEncoder().encode(gesture)\n        let jsonObject = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any])\n\n        XCTAssertEqual(jsonObject[\"enabled\"] as? Bool, true)\n        XCTAssertNil(jsonObject[\"button\"], \"legacy button should not be encoded\")\n        XCTAssertNotNil(jsonObject[\"trigger\"])\n        XCTAssertEqual(jsonObject[\"threshold\"] as? Int, 50)\n    }\n\n    // MARK: - Round-trip\n\n    func testRoundTrip() throws {\n        var gesture = Scheme.Buttons.Gesture()\n        var mapping = Scheme.Buttons.Mapping()\n        mapping.button = .mouse(3)\n        mapping.shift = true\n        gesture.trigger = mapping\n        gesture.threshold = 70\n        gesture.deadZone = 30\n        gesture.cooldownMs = 300\n        gesture.actions.left = .spaceLeft\n        gesture.actions.right = .spaceRight\n\n        let data = try JSONEncoder().encode(gesture)\n        let decoded = try JSONDecoder().decode(Scheme.Buttons.Gesture.self, from: data)\n\n        XCTAssertEqual(decoded.trigger?.button, .mouse(3))\n        XCTAssertEqual(decoded.trigger?.modifierFlags.contains(.maskShift), true)\n        XCTAssertEqual(decoded.threshold, 70)\n        XCTAssertEqual(decoded.deadZone, 30)\n        XCTAssertEqual(decoded.cooldownMs, 300)\n        XCTAssertEqual(decoded.actions.left, .spaceLeft)\n        XCTAssertEqual(decoded.actions.right, .spaceRight)\n    }\n\n    func testLegacyRoundTripMigrates() throws {\n        // Decode from legacy format\n        let gesture = try JSONDecoder().decode(\n            Scheme.Buttons.Gesture.self,\n            from: XCTUnwrap(#\"{\"enabled\":true,\"button\":2,\"threshold\":50}\"#.data(using: .utf8))\n        )\n\n        // Encode (should write enabled+trigger, not legacy button)\n        let data = try JSONEncoder().encode(gesture)\n        let jsonObject = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any])\n        XCTAssertEqual(jsonObject[\"enabled\"] as? Bool, true)\n        XCTAssertNil(jsonObject[\"button\"])\n        XCTAssertNotNil(jsonObject[\"trigger\"])\n\n        // Re-decode\n        let decoded = try JSONDecoder().decode(Scheme.Buttons.Gesture.self, from: data)\n        XCTAssertEqual(decoded.trigger?.button, .mouse(2))\n        XCTAssertEqual(decoded.threshold, 50)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Model/Scheme/Buttons/MappingActionKindTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class MappingActionKindTests: XCTestCase {\n    func testMappingActionKindReadsScrollKind() {\n        let action = Scheme.Buttons.Mapping.Action.arg1(.mouseWheelScrollRight(.pixel(20)))\n\n        XCTAssertEqual(action.kind, .mouseWheelScrollRight)\n    }\n\n    func testInitFromRunKindCreatesEmptyRunCommand() {\n        XCTAssertEqual(Scheme.Buttons.Mapping.Action(kind: .run), .arg1(.run(\"\")))\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Model/Scheme/Scrolling/BidirectionalTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class BidirectionalTests: XCTestCase {\n    private typealias Bidirectional = Scheme.Scrolling.Bidirectional\n\n    private struct Foo: Codable, Equatable {\n        var bar: String?\n    }\n\n    func testEncodeLiteral() throws {\n        let encoder = JSONEncoder()\n        encoder.outputFormatting = .sortedKeys\n\n        var foos = Bidirectional<Bool>()\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"null\"\n        )\n\n        foos.vertical = true\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"{\\\"vertical\\\":true}\"\n        )\n\n        foos.horizontal = true\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"true\"\n        )\n    }\n\n    func testEncodeStruct() throws {\n        let encoder = JSONEncoder()\n        encoder.outputFormatting = .sortedKeys\n\n        var foos = Bidirectional<Foo>()\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"null\"\n        )\n\n        foos.vertical = .init()\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"{\\\"vertical\\\":{}}\"\n        )\n\n        foos.horizontal = .init()\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"{}\"\n        )\n\n        foos.vertical = .init(bar: \"baz\")\n        XCTAssertEqual(\n            try String(data: encoder.encode(foos), encoding: .utf8),\n            \"{\\\"horizontal\\\":{},\\\"vertical\\\":{\\\"bar\\\":\\\"baz\\\"}}\"\n        )\n    }\n\n    func testDecodeLiteral() throws {\n        let decoder = JSONDecoder()\n\n        XCTAssertEqual(\n            try decoder.decode(Bidirectional<Bool>.self, from: Data(\"null\".utf8)),\n            .init()\n        )\n\n        XCTAssertEqual(\n            try decoder.decode(Bidirectional<Bool>.self, from: Data(\"{\\\"vertical\\\":true}\".utf8)),\n            .init(vertical: true)\n        )\n\n        XCTAssertEqual(\n            try decoder\n                .decode(Bidirectional<Bool>.self, from: Data(\"{\\\"horizontal\\\":false,\\\"vertical\\\":true}\".utf8)),\n            .init(vertical: true, horizontal: false)\n        )\n\n        XCTAssertEqual(\n            try decoder.decode(Bidirectional<Bool>.self, from: Data(\"true\".utf8)),\n            .init(vertical: true, horizontal: true)\n        )\n    }\n\n    func testDecodeStruct() throws {\n        let decoder = JSONDecoder()\n\n        XCTAssertEqual(\n            try decoder.decode(Bidirectional<Foo>.self, from: Data(\"{\\\"vertical\\\":{\\\"bar\\\":\\\"baz\\\"}}\".utf8)),\n            .init(vertical: .init(bar: \"baz\"))\n        )\n\n        XCTAssertEqual(\n            try decoder.decode(Bidirectional<Foo>.self, from: Data(\"{\\\"bar\\\":\\\"baz\\\"}\".utf8)),\n            .init(vertical: .init(bar: \"baz\"), horizontal: .init(bar: \"baz\"))\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Model/Scheme/Scrolling/DistanceModeTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class DistanceModeTests: XCTestCase {\n    func testAutoDistanceUsesByLinesMode() {\n        XCTAssertEqual(Scheme.Scrolling.Distance.auto.mode, .byLines)\n    }\n\n    func testPixelDistanceUsesByPixelsMode() {\n        XCTAssertEqual(Scheme.Scrolling.Distance.pixel(8).mode, .byPixels)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Model/Scheme/Scrolling/ModifiersKindTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class ModifiersKindTests: XCTestCase {\n    func testActionKindMapsPreventDefaultToNoAction() {\n        XCTAssertEqual(Scheme.Scrolling.Modifiers.Action.preventDefault.kind, .noAction)\n    }\n\n    func testInitFromDefaultActionKindCreatesAutoAction() {\n        XCTAssertEqual(Scheme.Scrolling.Modifiers.Action(kind: .defaultAction), .auto)\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/UI/ButtonMappingActionBindingTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport KeyKit\n@testable import LinearMouse\nimport SwiftUI\nimport XCTest\n\nfinal class ButtonMappingActionBindingTests: XCTestCase {\n    func testKindBindingReadsExistingActionKind() {\n        let binding = makeActionBinding(.arg1(.mouseWheelScrollLeft(.pixel(12))))\n\n        XCTAssertEqual(binding.kind.wrappedValue, .mouseWheelScrollLeft)\n    }\n\n    func testKindBindingWritesDefaultPayloadForScrollableAction() {\n        var action: Scheme.Buttons.Mapping.Action = .arg0(.auto)\n        let binding = makeActionBinding(action) { action = $0 }\n\n        binding.kind.wrappedValue = .mouseWheelScrollUp\n\n        XCTAssertEqual(action, .arg1(.mouseWheelScrollUp(.line(3))))\n    }\n\n    func testRunCommandBindingUpdatesCommand() {\n        var action: Scheme.Buttons.Mapping.Action = .arg1(.run(\"open\"))\n        let binding = makeActionBinding(action) { action = $0 }\n\n        binding.runCommand.wrappedValue = \"say hi\"\n\n        XCTAssertEqual(action, .arg1(.run(\"say hi\")))\n    }\n\n    func testScrollDistanceBindingUpdatesCurrentScrollAction() {\n        var action: Scheme.Buttons.Mapping.Action = .arg1(.mouseWheelScrollDown(.line(3)))\n        let binding = makeActionBinding(action) { action = $0 }\n\n        binding.scrollDistance.wrappedValue = .pixel(24)\n\n        XCTAssertEqual(action, .arg1(.mouseWheelScrollDown(.pixel(24))))\n    }\n\n    func testKeyPressKeysBindingUpdatesKeys() {\n        var action: Scheme.Buttons.Mapping.Action = .arg1(.keyPress([]))\n        let binding = makeActionBinding(action) { action = $0 }\n\n        binding.keyPressKeys.wrappedValue = [.command, .a]\n\n        XCTAssertEqual(action, .arg1(.keyPress([.command, .a])))\n    }\n\n    private func makeActionBinding(\n        _ action: Scheme.Buttons.Mapping.Action,\n        setter: @escaping (Scheme.Buttons.Mapping.Action) -> Void = { _ in }\n    ) -> Binding<Scheme.Buttons.Mapping.Action> {\n        Binding(\n            get: { action },\n            set: setter\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/UI/ModifierKeyActionPickerTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport SwiftUI\nimport XCTest\n\nfinal class ModifierKeyActionPickerTests: XCTestCase {\n    func testNilActionBindingDisplaysDefaultAction() {\n        let binding = makeActionBinding(action: nil)\n\n        XCTAssertEqual(binding.kind.wrappedValue, Scheme.Scrolling.Modifiers.Action.Kind.defaultAction)\n    }\n\n    func testSelectingDefaultActionStoresAutoAction() {\n        var action: Scheme.Scrolling.Modifiers.Action?\n        let binding = makeActionBinding(action: action) { action = $0 }\n\n        binding.kind.wrappedValue = .defaultAction\n\n        XCTAssertEqual(action, .auto)\n    }\n\n    func testSelectingNoActionStoresPreventDefaultAction() {\n        var action: Scheme.Scrolling.Modifiers.Action?\n        let binding = makeActionBinding(action: action) { action = $0 }\n\n        binding.kind.wrappedValue = .noAction\n\n        XCTAssertEqual(action, .preventDefault)\n    }\n\n    func testChangeSpeedFactorBindingRoundsToNearestHalfAboveOne() {\n        var action: Scheme.Scrolling.Modifiers.Action? = .changeSpeed(scale: 1)\n        let binding = makeActionBinding(action: action) { action = $0 }\n\n        binding.speedFactor.wrappedValue = 2.74\n\n        XCTAssertEqual(action, .changeSpeed(scale: 2.5))\n    }\n\n    private func makeActionBinding(\n        action: Scheme.Scrolling.Modifiers.Action?,\n        setter: @escaping (Scheme.Scrolling.Modifiers.Action?) -> Void = { _ in }\n    ) -> Binding<Scheme.Scrolling.Modifiers.Action?> {\n        Binding(\n            get: { action },\n            set: setter\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/UI/ScrollingDistanceBindingTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport SwiftUI\nimport XCTest\n\nfinal class ScrollingDistanceBindingTests: XCTestCase {\n    func testModeBindingReadsAutoAsByLines() {\n        let binding = makeDistanceBinding(.auto)\n\n        XCTAssertEqual(binding.mode.wrappedValue, .byLines)\n    }\n\n    func testModeBindingWritesPixelDefault() {\n        var distance: Scheme.Scrolling.Distance = .line(3)\n        let binding = makeDistanceBinding(distance) { distance = $0 }\n\n        binding.mode.wrappedValue = .byPixels\n\n        XCTAssertEqual(distance, .pixel(36))\n    }\n\n    func testLineCountBindingUpdatesDistance() {\n        var distance: Scheme.Scrolling.Distance = .line(3)\n        let binding = makeDistanceBinding(distance) { distance = $0 }\n\n        binding.lineCount.wrappedValue = 7\n\n        XCTAssertEqual(distance, .line(7))\n    }\n\n    func testPixelCountBindingRoundsToSingleDecimalPlace() {\n        var distance: Scheme.Scrolling.Distance = .pixel(10)\n        let binding = makeDistanceBinding(distance) { distance = $0 }\n\n        binding.pixelCount.wrappedValue = 12.34\n\n        XCTAssertEqual(distance, .pixel(12.3))\n    }\n\n    private func makeDistanceBinding(\n        _ distance: Scheme.Scrolling.Distance,\n        setter: @escaping (Scheme.Scrolling.Distance) -> Void = { _ in }\n    ) -> Binding<Scheme.Scrolling.Distance> {\n        Binding(\n            get: { distance },\n            set: setter\n        )\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/UI/StatusItemBatteryIndicatorTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n@testable import LinearMouse\nimport PointerKit\nimport XCTest\n\nfinal class StatusItemBatteryIndicatorTests: XCTestCase {\n    func testMenuBarBatteryTitleDisabledReturnsNil() {\n        XCTAssertNil(StatusItem.menuBarBatteryTitle(currentBatteryLevel: 12, mode: .off))\n    }\n\n    func testMenuBarBatteryTitleHiddenAboveThreshold() {\n        XCTAssertNil(StatusItem.menuBarBatteryTitle(currentBatteryLevel: 21, mode: .below20))\n    }\n\n    func testMenuBarBatteryTitleShownAtThreshold() {\n        XCTAssertEqual(StatusItem.menuBarBatteryTitle(currentBatteryLevel: 20, mode: .below20), \"20%\")\n    }\n\n    func testMenuBarBatteryTitleAlwaysShowMode() {\n        XCTAssertEqual(StatusItem.menuBarBatteryTitle(currentBatteryLevel: 100, mode: .always), \"100%\")\n    }\n\n    func testMenuBarBatteryDevicePrefersActiveDeviceOverSelectedDevice() {\n        let activeDevice = NSObject()\n        let selectedDevice = NSObject()\n\n        XCTAssertTrue(\n            StatusItem.menuBarBatteryDevice(\n                activeDeviceRef: WeakRef(activeDevice),\n                selectedDeviceRef: WeakRef(selectedDevice)\n            ) === activeDevice\n        )\n    }\n\n    func testMenuBarBatteryDeviceFallsBackToSelectedDevice() {\n        let selectedDevice = NSObject()\n\n        XCTAssertTrue(\n            StatusItem.menuBarBatteryDevice(\n                activeDeviceRef: nil,\n                selectedDeviceRef: WeakRef(selectedDevice)\n            ) === selectedDevice\n        )\n    }\n\n    func testCurrentDeviceBatteryLevelUsesLowestReceiverBattery() {\n        let pairedDevices = [\n            ReceiverLogicalDeviceIdentity(\n                receiverLocationID: 1,\n                slot: 1,\n                kind: .mouse,\n                name: \"Mouse A\",\n                serialNumber: nil,\n                productID: nil,\n                batteryLevel: 60\n            ),\n            ReceiverLogicalDeviceIdentity(\n                receiverLocationID: 1,\n                slot: 2,\n                kind: .mouse,\n                name: \"Mouse B\",\n                serialNumber: nil,\n                productID: nil,\n                batteryLevel: 15\n            )\n        ]\n\n        let inventory = [\n            ConnectedBatteryDeviceInfo(id: \"receiver|1|1\", name: \"Mouse A\", batteryLevel: 60),\n            ConnectedBatteryDeviceInfo(id: \"receiver|1|2\", name: \"Mouse B\", batteryLevel: 15)\n        ]\n\n        XCTAssertEqual(\n            ConnectedBatteryDeviceInfo.currentDeviceBatteryLevel(\n                pairedDevices: pairedDevices,\n                directDeviceIdentity: nil,\n                inventory: inventory\n            ),\n            15\n        )\n    }\n\n    func testCurrentDeviceBatteryLevelFallsBackToDirectDeviceInventory() {\n        let inventory = [\n            ConnectedBatteryDeviceInfo(id: \"device-1\", name: \"MX Master 3\", batteryLevel: 18)\n        ]\n\n        XCTAssertEqual(\n            ConnectedBatteryDeviceInfo.currentDeviceBatteryLevel(\n                pairedDevices: [],\n                directDeviceIdentity: \"device-1\",\n                inventory: inventory\n            ),\n            18\n        )\n    }\n\n    func testAppleBluetoothDeviceDetection() {\n        XCTAssertTrue(ConnectedBatteryDeviceInfo.isAppleBluetoothDevice(\n            vendorID: 0x004C,\n            transport: PointerDeviceTransportName.bluetooth\n        ))\n        XCTAssertFalse(ConnectedBatteryDeviceInfo.isAppleBluetoothDevice(\n            vendorID: 0x004C,\n            transport: PointerDeviceTransportName.bluetoothLowEnergy\n        ))\n        XCTAssertFalse(ConnectedBatteryDeviceInfo.isAppleBluetoothDevice(\n            vendorID: 0x046D,\n            transport: PointerDeviceTransportName.bluetooth\n        ))\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Utilities/Codable/ImplicitOptionalTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class ImplicitOptionalTests: XCTestCase {\n    fileprivate struct Foo: Codable, Equatable {\n        @ImplicitOptional var bar: Bar\n\n        init() {}\n\n        init(bar: Bar? = nil) {\n            $bar = bar\n        }\n    }\n\n    fileprivate struct Bar: Codable, Equatable {\n        @ImplicitOptional var baz: Baz\n\n        init() {}\n\n        init(baz: Baz? = nil) {\n            $baz = baz\n        }\n    }\n\n    fileprivate struct Baz: Codable, Equatable {\n        var qux: Int\n    }\n\n    func testEncodingNil() throws {\n        let encoder = JSONEncoder()\n        XCTAssertEqual(\n            try String(bytes: encoder.encode(Foo()), encoding: .utf8),\n            \"{}\"\n        )\n    }\n\n    func testEncodingNestedNil() throws {\n        let encoder = JSONEncoder()\n        XCTAssertEqual(\n            try String(bytes: encoder.encode(Foo(bar: Bar())), encoding: .utf8),\n            \"{\\\"bar\\\":{}}\"\n        )\n    }\n\n    func testNestedAssignment() {\n        var foo = Foo()\n        foo.bar.baz.qux += 1\n        XCTAssertEqual(foo.bar.baz.qux, 43)\n    }\n\n    func testDecodeNil() throws {\n        let decoder = JSONDecoder()\n        let foo = try decoder.decode(Foo.self, from: Data(\"{\\\"bar\\\":{}}\".utf8))\n        XCTAssertNil(foo.bar.$baz)\n    }\n}\n\nextension ImplicitOptionalTests.Foo: ImplicitInitable {}\n\nextension ImplicitOptionalTests.Bar: ImplicitInitable {}\n\nextension ImplicitOptionalTests.Baz: ImplicitInitable {\n    init() {\n        qux = 42\n    }\n}\n"
  },
  {
    "path": "LinearMouseUnitTests/Utilities/KeyboardSettingsSnapshotTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import LinearMouse\nimport XCTest\n\nfinal class KeyboardSettingsSnapshotTests: XCTestCase {\n    func testKeyRepeatTimingCanBeReadOffMainThreadAfterMainThreadRefresh() {\n        let refreshed = expectation(description: \"Refresh key repeat timing on main thread\")\n        DispatchQueue.main.async {\n            KeyboardSettingsSnapshot.shared.refresh()\n            refreshed.fulfill()\n        }\n        wait(for: [refreshed], timeout: 5)\n\n        let readSnapshot = expectation(description: \"Read key repeat timing off the main thread\")\n        DispatchQueue.global(qos: .userInitiated).async {\n            _ = KeyboardSettingsSnapshot.shared.keyRepeatDelay\n            _ = KeyboardSettingsSnapshot.shared.keyRepeatInterval\n            readSnapshot.fulfill()\n        }\n\n        wait(for: [readSnapshot], timeout: 5)\n    }\n}\n"
  },
  {
    "path": "Makefile",
    "content": "BUILD_DIR = $(CURDIR)/build\nARCHIVE_PATH = $(CURDIR)/build/LinearMouse.xcarchive\nTARGET_DIR = $(CURDIR)/build/target\nTARGET_DMG = $(CURDIR)/build/LinearMouse.dmg\nXCODEBUILD_ARGS ?=\n\nall: configure clean lint test package\n\nconfigure: Signing.xcconfig Version.xcconfig .git/hooks/pre-commit\n\nconfigure-release: configure Release.xcconfig\n\nSigning.xcconfig:\n\t@./Scripts/configure-code-signing\n\nVersion.xcconfig:\n\t@./Scripts/configure-version\n\nRelease.xcconfig:\n\t@./Scripts/configure-release\n\n.git/hooks/pre-commit:\n\tcp ./Scripts/pre-commit $@\n\nclean:\n\trm -fr build\n\nlint:\n\tswiftformat --lint .\n\tswiftlint .\n\ntest:\n\txcodebuild test -project LinearMouse.xcodeproj -scheme LinearMouse $(XCODEBUILD_ARGS)\n\npackage: $(TARGET_DMG)\n\n$(BUILD_DIR)/Release/LinearMouse.app:\n\txcodebuild archive -project LinearMouse.xcodeproj -scheme LinearMouse -archivePath '$(ARCHIVE_PATH)' $(XCODEBUILD_ARGS)\n\txcodebuild -exportArchive -archivePath '$(ARCHIVE_PATH)' -exportOptionsPlist ExportOptions.plist -exportPath '$(BUILD_DIR)/Release'\n\n$(TARGET_DMG): $(BUILD_DIR)/Release/LinearMouse.app\n\trm -rf '$(TARGET_DIR)'\n\trm -f '$(TARGET_DMG)'\n\tmkdir '$(TARGET_DIR)'\n\tcp -a '$(BUILD_DIR)/Release/LinearMouse.app' '$(TARGET_DIR)'\n\tln -s /Applications '$(TARGET_DIR)/'\n\thdiutil create -format UDBZ -srcfolder '$(TARGET_DIR)/' -volname LinearMouse '$(TARGET_DMG)'\n\nprepublish: package\n\t@./Scripts/sign-and-notarize\n\n.PHONY: all configure test build clean package\n"
  },
  {
    "path": "Modules/DockKit/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/config/registries.json\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n.netrc\n"
  },
  {
    "path": "Modules/DockKit/Package.swift",
    "content": "// swift-tools-version: 5.6\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"DockKit\",\n    products: [\n        .library(\n            name: \"DockKit\",\n            targets: [\"DockKit\"]\n        )\n    ],\n    dependencies: [\n    ],\n    targets: [\n        .target(\n            name: \"DockKitC\",\n            dependencies: [],\n            linkerSettings: [\n                .linkedFramework(\"ApplicationServices\")\n            ]\n        ),\n        .target(\n            name: \"DockKit\",\n            dependencies: [\"DockKitC\"]\n        ),\n        .testTarget(\n            name: \"DockKitTests\",\n            dependencies: [\"DockKit\"]\n        )\n    ]\n)\n"
  },
  {
    "path": "Modules/DockKit/README.md",
    "content": "# DockKit\n\nPrivate APIs for Dock.\n"
  },
  {
    "path": "Modules/DockKit/Sources/DockKit/DockKit.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport DockKitC\nimport Foundation\n\npublic func launchpad() {\n    CoreDockSendNotification(\"com.apple.launchpad.toggle\" as CFString, 0)\n}\n\npublic func missionControl() {\n    CoreDockSendNotification(\"com.apple.expose.awake\" as CFString, 0)\n}\n\npublic func showDesktop() {\n    CoreDockSendNotification(\"com.apple.showdesktop.awake\" as CFString, 0)\n}\n\npublic func appExpose() {\n    CoreDockSendNotification(\"com.apple.expose.front.awake\" as CFString, 0)\n}\n"
  },
  {
    "path": "Modules/DockKit/Sources/DockKitC/DockKitC.m",
    "content": "//\n//  DockKitC.m\n//  \n//\n//  Created by Jiahao Lu on 2022/7/26.\n//\n\n#import <Foundation/Foundation.h>\n"
  },
  {
    "path": "Modules/DockKit/Sources/DockKitC/include/ApplicationServicesSPI.h",
    "content": "//\n//  Header.h\n//  \n//\n//  Created by Jiahao Lu on 2022/7/26.\n//\n\n#ifndef APPLICATION_SERVICES_SPI_H\n#define APPLICATION_SERVICES_SPI_H\n\n#import <ApplicationServices/ApplicationServices.h>\n\nextern CGError CoreDockSendNotification(CFStringRef notification, int unknown);\n\n#endif /* APPLICATION_SERVICES_SPI_H */\n"
  },
  {
    "path": "Modules/DockKit/Tests/DockKitTests/DockKitTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import DockKit\nimport XCTest\n\nfinal class DockKitTests: XCTestCase {\n    func testLaunchpad() {\n        launchpad()\n    }\n\n    func testMissionControl() {\n        missionControl()\n    }\n\n    func testShowDesktop() {\n        showDesktop()\n    }\n\n    func testAppExpose() {\n        appExpose()\n    }\n}\n"
  },
  {
    "path": "Modules/GestureKit/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/config/registries.json\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n.netrc\n"
  },
  {
    "path": "Modules/GestureKit/Package.swift",
    "content": "// swift-tools-version: 5.6\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"GestureKit\",\n    products: [\n        // Products define the executables and libraries a package produces, and make them visible to other packages.\n        .library(\n            name: \"GestureKit\",\n            targets: [\"GestureKit\"]\n        )\n    ],\n    dependencies: [\n        // Dependencies declare other packages that this package depends on.\n        // .package(url: /* package url */, from: \"1.0.0\"),\n    ],\n    targets: [\n        // Targets are the basic building blocks of a package. A target can define a module or a test suite.\n        // Targets can depend on other targets in this package, and on products in packages this package depends on.\n        .target(\n            name: \"GestureKit\",\n            dependencies: []\n        ),\n        .testTarget(\n            name: \"GestureKitTests\",\n            dependencies: [\"GestureKit\"]\n        )\n    ]\n)\n"
  },
  {
    "path": "Modules/GestureKit/README.md",
    "content": "# GestureKit\n\nA set of `CGEvent` extensions to simulate gesture events.\n"
  },
  {
    "path": "Modules/GestureKit/Sources/GestureKit/CGEventField+Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\n\n/// - SeeAlso:\n/// https://github.com/WebKit/WebKit/blob/ab59722dc517c798f7d88bfe4dcb7b33b8473e7e/Tools/TestRunnerShared/spi/CoreGraphicsTestSPI.h#L39\nextension CGEventField {\n    static let gestureHIDType = Self(rawValue: 110)!\n    static let gestureZoomValue = Self(rawValue: 113)!\n    static let gestureSwipeValue = Self(rawValue: 115)!\n    static let gesturePhase = Self(rawValue: 132)!\n}\n\n/// - SeeAlso:\n/// https://github.com/WebKit/WebKit/blob/ab59722dc517c798f7d88bfe4dcb7b33b8473e7e/Tools/TestRunnerShared/spi/CoreGraphicsTestSPI.h#L87\npublic enum CGSGesturePhase: UInt8 {\n    case none = 0\n    case began = 1\n    case changed = 2\n    case ended = 4\n    case cancelled = 8\n    case mayBegin = 128\n}\n\n/// - SeeAlso:\n/// https://github.com/WebKit/WebKit/blob/52d85940c6acce0f6b25fe1f8155c25283058e27/Source/WebCore/PAL/pal/spi/mac/IOKitSPIMac.h#L74\nenum IOHIDEventType: UInt32 {\n    case none\n    case vendorDefined\n    case keyboard = 3\n    case rotation = 5\n    case scroll = 6\n    case zoom = 8\n    case digitizer = 11\n    case navigationSwipe = 16\n    case zoomToggle = 22\n    case force = 32\n}\n\n/// - SeeAlso:\n/// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-368.13/IOHIDFamily/IOHIDEventTypes.h.auto.html\npublic enum IOHIDSwipeMask: UInt32 {\n    case swipeUp = 0x01\n    case swipeDown = 0x02\n    case swipeLeft = 0x04\n    case swipeRight = 0x08\n    case scaleExpand = 0x10\n    case scaleContract = 0x20\n    case rotateCW = 0x40\n    case rotateCCW = 0x80\n}\n"
  },
  {
    "path": "Modules/GestureKit/Sources/GestureKit/CGEventType+Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\n\npublic extension CGEventType {\n    init?(nsEventType: NSEvent.EventType) {\n        self.init(rawValue: UInt32(nsEventType.rawValue))\n    }\n}\n"
  },
  {
    "path": "Modules/GestureKit/Sources/GestureKit/GestureEvent+NavigationSwipe.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\n\npublic extension GestureEvent {\n    convenience init?(navigationSwipeSource: CGEventSource?, direction: IOHIDSwipeMask) {\n        guard let swipeBeganEvent = CGEvent(source: navigationSwipeSource) else {\n            return nil\n        }\n\n        guard let swipeEndedEvent = CGEvent(source: navigationSwipeSource) else {\n            return nil\n        }\n\n        swipeBeganEvent.type = .init(nsEventType: .gesture)!\n        swipeBeganEvent.setIntegerValueField(.gestureHIDType, value: Int64(IOHIDEventType.navigationSwipe.rawValue))\n        swipeBeganEvent.setIntegerValueField(.gesturePhase, value: Int64(CGSGesturePhase.began.rawValue))\n        swipeBeganEvent.setIntegerValueField(.gestureSwipeValue, value: Int64(direction.rawValue))\n\n        swipeEndedEvent.type = .init(nsEventType: .gesture)!\n        swipeEndedEvent.setIntegerValueField(.gestureHIDType, value: Int64(IOHIDEventType.navigationSwipe.rawValue))\n        swipeEndedEvent.setIntegerValueField(.gesturePhase, value: Int64(CGSGesturePhase.ended.rawValue))\n\n        self.init(cgEvents: [swipeBeganEvent, swipeEndedEvent])\n    }\n}\n"
  },
  {
    "path": "Modules/GestureKit/Sources/GestureKit/GestureEvent+Zoom.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreGraphics\n\npublic extension GestureEvent {\n    convenience init?(zoomToggleSource: CGEventSource?) {\n        guard let event = CGEvent(source: zoomToggleSource) else {\n            return nil\n        }\n\n        event.type = .init(nsEventType: .gesture)!\n        event.setIntegerValueField(.gestureHIDType, value: Int64(IOHIDEventType.zoomToggle.rawValue))\n\n        self.init(cgEvents: [event])\n    }\n\n    convenience init?(zoomSource: CGEventSource?, phase: CGSGesturePhase, magnification: Double) {\n        guard let event = CGEvent(source: zoomSource) else {\n            return nil\n        }\n\n        event.type = .init(nsEventType: .gesture)!\n        event.flags = []\n        event.setIntegerValueField(.gestureHIDType, value: Int64(IOHIDEventType.zoom.rawValue))\n        event.setIntegerValueField(.gesturePhase, value: Int64(phase.rawValue))\n        event.setDoubleValueField(.gestureZoomValue, value: magnification)\n\n        self.init(cgEvents: [event])\n    }\n}\n"
  },
  {
    "path": "Modules/GestureKit/Sources/GestureKit/GestureEvent.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport CoreGraphics\n\npublic class GestureEvent {\n    let cgEvents: [CGEvent]\n\n    init(cgEvents: [CGEvent]) {\n        self.cgEvents = cgEvents\n    }\n\n    public func post(tap: CGEventTapLocation) {\n        for cgEvent in cgEvents {\n            cgEvent.post(tap: tap)\n        }\n    }\n}\n"
  },
  {
    "path": "Modules/GestureKit/Tests/GestureKitTests/GestureKitTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import GestureKit\nimport XCTest\n\nfinal class GestureKitTests: XCTestCase {\n    func testNavigationSwipeGesture() throws {\n        guard let event = GestureEvent(navigationSwipeSource: nil, direction: .swipeLeft) else {\n            XCTFail(\"event should not be nil\")\n            return\n        }\n\n        let cgEvents = event.cgEvents\n        XCTAssertEqual(cgEvents.count, 2)\n\n        for (index, cgEvent) in cgEvents.enumerated() {\n            let nsEvent = try XCTUnwrap(NSEvent(cgEvent: cgEvent))\n            XCTAssertEqual(nsEvent.type, .swipe)\n            switch index {\n            case 0:\n                XCTAssertEqual(nsEvent.phase, .began)\n            case 1:\n                XCTAssertEqual(nsEvent.phase, .ended)\n            default:\n                break\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Modules/KeyKit/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/config/registries.json\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n.netrc\n"
  },
  {
    "path": "Modules/KeyKit/Package.swift",
    "content": "// swift-tools-version: 5.6\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"KeyKit\",\n    platforms: [\n        .macOS(.v10_15)\n    ],\n    products: [\n        .library(\n            name: \"KeyKit\",\n            targets: [\"KeyKit\"]\n        )\n    ],\n    dependencies: [],\n    targets: [\n        .target(\n            name: \"KeyKitC\",\n            dependencies: []\n        ),\n        .target(\n            name: \"KeyKit\",\n            dependencies: [\"KeyKitC\"]\n        ),\n        .testTarget(\n            name: \"KeyKitTests\",\n            dependencies: [\"KeyKit\"]\n        )\n    ]\n)\n"
  },
  {
    "path": "Modules/KeyKit/README.md",
    "content": "# KeyKit\n\nPost keys, symbolic hotkeys and system defined keys such as media keys.\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKit/Key.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\npublic enum Key: String, Codable {\n    case enter\n    case tab\n    case space\n    case delete\n    case escape\n    case command\n    case shift\n    case capsLock\n    case option\n    case control\n    case commandRight\n    case shiftRight\n    case optionRight\n    case controlRight\n    case arrowLeft\n    case arrowRight\n    case arrowDown\n    case arrowUp\n    case home\n    case pageUp\n    case backspace\n    case end\n    case pageDown\n    case f1\n    case f2\n    case f3\n    case f4\n    case f5\n    case f6\n    case f7\n    case f8\n    case f9\n    case f10\n    case f11\n    case f12\n    case a\n    case b\n    case c\n    case d\n    case e\n    case f\n    case g\n    case h\n    case i\n    case j\n    case k\n    case l\n    case m\n    case n\n    case o\n    case p\n    case q\n    case r\n    case s\n    case t\n    case u\n    case v\n    case w\n    case x\n    case y\n    case z\n    // Extended Latin keyboards (used for multiple languages):\n    case ê\n    case é\n    case î\n    case ô\n    case û\n    case ó\n    case ö\n    case ä\n    // German keyboards:\n    case ü\n    case ß\n    // Spanish keyboards:\n    case á\n    case í\n    case ú\n    case ñ\n    // French keyboards:\n    case ç\n    case à\n    case è\n    case ù\n    // Norwegian/Danish keyboards:\n    case ã\n    case õ\n    /// Swedish/Finnish keyboards:\n    case å\n    // Polish keyboards:\n    case ą\n    case ć\n    case ę\n    case ł\n    case ń\n    case ś\n    case ź\n    case ż\n    case zero = \"0\"\n    case one = \"1\"\n    case two = \"2\"\n    case three = \"3\"\n    case four = \"4\"\n    case five = \"5\"\n    case six = \"6\"\n    case seven = \"7\"\n    case eight = \"8\"\n    case nine = \"9\"\n    case equal = \"=\"\n    case minus = \"-\"\n    case semicolon = \";\"\n    case quote = \"'\"\n    case comma = \",\"\n    case period = \".\"\n    case slash = \"/\"\n    case backslash = \"\\\\\"\n    case backquote = \"`\"\n    case backetLeft = \"[\"\n    case backetRight = \"]\"\n    case numpadPlus\n    case numpadMinus\n    case numpadMultiply\n    case numpadDivide\n    case numpadEnter\n    case numpadEquals\n    case numpadDecimal\n    case numpadClear\n    case numpad0\n    case numpad1\n    case numpad2\n    case numpad3\n    case numpad4\n    case numpad5\n    case numpad6\n    case numpad7\n    case numpad8\n    case numpad9\n}\n\nextension Key {\n    private static let modifiersKeys: Set<Key> = [.command, .shift, .option, .control,\n                                                  .commandRight, .shiftRight, .optionRight, .controlRight]\n\n    public var isModifier: Bool {\n        Self.modifiersKeys.contains(self)\n    }\n}\n\nextension Key: CustomStringConvertible {\n    public var description: String {\n        switch self {\n        case .enter:\n            return \"↩\"\n        case .command:\n            return \"⌘\"\n        case .commandRight:\n            return \"Right ⌘\"\n        case .shift:\n            return \"⇧\"\n        case .shiftRight:\n            return \"Right ⇧\"\n        case .option:\n            return \"⌥\"\n        case .optionRight:\n            return \"Right ⌥\"\n        case .control:\n            return \"⌃\"\n        case .controlRight:\n            return \"Right ⌃\"\n        case .numpadPlus:\n            return \"Numpad +\"\n        case .numpadMinus:\n            return \"Numpad -\"\n        case .numpadMultiply:\n            return \"Numpad *\"\n        case .numpadDivide:\n            return \"Numpad /\"\n        case .numpadEnter:\n            return \"Numpad Enter\"\n        case .numpadEquals:\n            return \"Numpad =\"\n        case .numpadDecimal:\n            return \"Numpad .\"\n        case .numpadClear:\n            return \"Numpad Clear\"\n        case .numpad0:\n            return \"Numpad 0\"\n        case .numpad1:\n            return \"Numpad 1\"\n        case .numpad2:\n            return \"Numpad 2\"\n        case .numpad3:\n            return \"Numpad 3\"\n        case .numpad4:\n            return \"Numpad 4\"\n        case .numpad5:\n            return \"Numpad 5\"\n        case .numpad6:\n            return \"Numpad 6\"\n        case .numpad7:\n            return \"Numpad 7\"\n        case .numpad8:\n            return \"Numpad 8\"\n        case .numpad9:\n            return \"Numpad 9\"\n        default:\n            return rawValue.prefix(1).capitalized + rawValue.dropFirst()\n        }\n    }\n}\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKit/KeyCodeResolver.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Carbon\nimport Combine\nimport Foundation\n\n/// Keyboard layout-independent key code resolver.\npublic class KeyCodeResolver {\n    private var subscriptions = Set<AnyCancellable>()\n    private let mappingLock = NSLock()\n    private var mapping: [String: CGKeyCode] = [:]\n    private var reversedMapping: [CGKeyCode: Key] = [:]\n\n    public init() {\n        DistributedNotificationCenter.default\n            .publisher(for: .init(kTISNotifyEnabledKeyboardInputSourcesChanged as String))\n            .sink { [weak self] _ in\n                self?.scheduleMappingUpdate(after: 0.1)\n            }\n            .store(in: &subscriptions)\n\n        DistributedNotificationCenter.default\n            .publisher(for: .init(kTISNotifySelectedKeyboardInputSourceChanged as String))\n            .sink { [weak self] _ in\n                self?.scheduleMappingUpdate(after: 0.1)\n            }\n            .store(in: &subscriptions)\n\n        // `NSEvent.characters` below asserts on the main thread.\n        if Thread.isMainThread {\n            updateMapping()\n        } else {\n            DispatchQueue.main.sync { updateMapping() }\n        }\n    }\n\n    private func scheduleMappingUpdate(after delay: TimeInterval) {\n        DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in\n            self?.updateMapping()\n        }\n    }\n\n    private func updateMapping() {\n        var newMapping: [String: CGKeyCode] = [:]\n        var newReversedMapping: [CGKeyCode: Key] = [:]\n\n        for keyCode: CGKeyCode in 0 ..< 128 {\n            guard let cgEvent = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: true) else {\n                continue\n            }\n            cgEvent.flags = []\n            guard let nsEvent = NSEvent(cgEvent: cgEvent) else {\n                continue\n            }\n            guard nsEvent.type == .keyDown else {\n                continue\n            }\n            guard let characters = nsEvent.characters, characters.count == 1 else {\n                continue\n            }\n            guard newMapping[characters] == nil else {\n                continue\n            }\n            newMapping[characters] = keyCode\n        }\n\n        newMapping[Key.enter.rawValue] = 0x24\n        newMapping[Key.tab.rawValue] = 0x30\n        newMapping[Key.space.rawValue] = 0x31\n        newMapping[Key.delete.rawValue] = 0x33\n        newMapping[Key.escape.rawValue] = 0x35\n        newMapping[Key.commandRight.rawValue] = 0x36\n        newMapping[Key.command.rawValue] = 0x37\n        newMapping[Key.shift.rawValue] = 0x38\n        newMapping[Key.capsLock.rawValue] = 0x39\n        newMapping[Key.option.rawValue] = 0x3A\n        newMapping[Key.control.rawValue] = 0x3B\n        newMapping[Key.shiftRight.rawValue] = 0x3C\n        newMapping[Key.optionRight.rawValue] = 0x3D\n        newMapping[Key.controlRight.rawValue] = 0x3E\n        newMapping[Key.arrowLeft.rawValue] = 0x7B\n        newMapping[Key.arrowRight.rawValue] = 0x7C\n        newMapping[Key.arrowDown.rawValue] = 0x7D\n        newMapping[Key.arrowUp.rawValue] = 0x7E\n        newMapping[Key.home.rawValue] = 0x73\n        newMapping[Key.pageUp.rawValue] = 0x74\n        newMapping[Key.backspace.rawValue] = 0x75\n        newMapping[Key.end.rawValue] = 0x77\n        newMapping[Key.pageDown.rawValue] = 0x79\n        newMapping[Key.f1.rawValue] = 0x7A\n        newMapping[Key.f2.rawValue] = 0x78\n        newMapping[Key.f3.rawValue] = 0x63\n        newMapping[Key.f4.rawValue] = 0x76\n        newMapping[Key.f5.rawValue] = 0x60\n        newMapping[Key.f6.rawValue] = 0x61\n        newMapping[Key.f7.rawValue] = 0x62\n        newMapping[Key.f8.rawValue] = 0x64\n        newMapping[Key.f9.rawValue] = 0x65\n        newMapping[Key.f10.rawValue] = 0x6D\n        newMapping[Key.f11.rawValue] = 0x67\n        newMapping[Key.f12.rawValue] = 0x6F\n        newMapping[Key.numpadPlus.rawValue] = 0x45\n        newMapping[Key.numpadMinus.rawValue] = 0x4E\n        newMapping[Key.numpadMultiply.rawValue] = 0x43\n        newMapping[Key.numpadDivide.rawValue] = 0x4B\n        newMapping[Key.numpadEnter.rawValue] = 0x4C\n        newMapping[Key.numpadEquals.rawValue] = 0x51\n        newMapping[Key.numpadDecimal.rawValue] = 0x41\n        newMapping[Key.numpadClear.rawValue] = 0x47\n        newMapping[Key.numpad0.rawValue] = 0x52\n        newMapping[Key.numpad1.rawValue] = 0x53\n        newMapping[Key.numpad2.rawValue] = 0x54\n        newMapping[Key.numpad3.rawValue] = 0x55\n        newMapping[Key.numpad4.rawValue] = 0x56\n        newMapping[Key.numpad5.rawValue] = 0x57\n        newMapping[Key.numpad6.rawValue] = 0x58\n        newMapping[Key.numpad7.rawValue] = 0x59\n        newMapping[Key.numpad8.rawValue] = 0x5B\n        newMapping[Key.numpad9.rawValue] = 0x5C\n        for (keyString, keyCode) in newMapping {\n            guard let key = Key(rawValue: keyString) else {\n                continue\n            }\n            newReversedMapping[keyCode] = key\n        }\n\n        mappingLock.withLock {\n            mapping = newMapping\n            reversedMapping = newReversedMapping\n        }\n    }\n\n    public func keyCode(for key: Key) -> CGKeyCode? {\n        mappingLock.withLock { mapping[key.rawValue] }\n    }\n\n    public func key(from keyCode: CGKeyCode) -> Key? {\n        mappingLock.withLock { reversedMapping[keyCode] }\n    }\n}\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKit/KeySimulator.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\n\npublic enum KeySimulatorError: Error {\n    case unsupportedKey\n}\n\n/// Abstracts `KeySimulator` so call sites can inject a recorder/mock and avoid posting real key\n/// events from unit tests.\npublic protocol KeySimulating: AnyObject {\n    func down(keys: [Key], tap: CGEventTapLocation?) throws\n    func up(keys: [Key], tap: CGEventTapLocation?) throws\n    func press(keys: [Key], tap: CGEventTapLocation?) throws\n    func reset()\n    func modifiedCGEventFlags(of event: CGEvent) -> CGEventFlags?\n}\n\n/// Simulate key presses.\npublic class KeySimulator: KeySimulating {\n    private let keyCodeResolver = KeyCodeResolver()\n    private let lock = NSLock()\n\n    private var flags = CGEventFlags()\n\n    public init() {}\n\n    private func postKeyLocked(_ key: Key, keyDown: Bool, tap: CGEventTapLocation? = nil) throws {\n        var flagsToToggle = CGEventFlags()\n        switch key {\n        case .command, .commandRight:\n            flagsToToggle.insert(.maskCommand)\n            flagsToToggle.insert(.init(rawValue: UInt64(key == .command ? NX_DEVICELCMDKEYMASK : NX_DEVICERCMDKEYMASK)))\n        case .shift, .shiftRight:\n            flagsToToggle.insert(.maskShift)\n            flagsToToggle\n                .insert(.init(rawValue: UInt64(key == .shift ? NX_DEVICELSHIFTKEYMASK : NX_DEVICERSHIFTKEYMASK)))\n        case .option, .optionRight:\n            flagsToToggle.insert(.maskAlternate)\n            flagsToToggle.insert(.init(rawValue: UInt64(key == .option ? NX_DEVICELALTKEYMASK : NX_DEVICERALTKEYMASK)))\n        case .control, .controlRight:\n            flagsToToggle.insert(.maskControl)\n            flagsToToggle.insert(.init(rawValue: UInt64(key == .control ? NX_DEVICELCTLKEYMASK : NX_DEVICERCTLKEYMASK)))\n        default:\n            break\n        }\n\n        if !flagsToToggle.isEmpty {\n            if keyDown {\n                flags.insert(flagsToToggle)\n            } else {\n                flags.remove(flagsToToggle)\n            }\n        }\n\n        switch key {\n        case .capsLock:\n            postSystemDefinedKey(.capsLock, keyDown: keyDown)\n            return\n        default:\n            break\n        }\n\n        guard let keyCode = keyCodeResolver.keyCode(for: key) else {\n            throw KeySimulatorError.unsupportedKey\n        }\n\n        guard let event = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: keyDown) else {\n            return\n        }\n\n        event.flags = event.flags\n            .subtracting([.maskCommand, .maskShift, .maskAlternate, .maskControl])\n            .union(flags)\n\n        if !flagsToToggle.isEmpty {\n            event.type = .flagsChanged\n        }\n\n        event.post(tap: tap ?? .cghidEventTap)\n    }\n}\n\npublic extension KeySimulator {\n    func reset() {\n        lock.withLock {\n            flags = []\n        }\n    }\n\n    func down(keys: [Key], tap: CGEventTapLocation? = nil) throws {\n        try lock.withLock {\n            for key in keys {\n                try postKeyLocked(key, keyDown: true, tap: tap)\n            }\n        }\n    }\n\n    func down(_ keys: Key..., tap: CGEventTapLocation? = nil) throws {\n        try down(keys: keys, tap: tap)\n    }\n\n    func up(keys: [Key], tap: CGEventTapLocation? = nil) throws {\n        try lock.withLock {\n            for key in keys {\n                try postKeyLocked(key, keyDown: false, tap: tap)\n            }\n        }\n    }\n\n    func up(_ keys: Key..., tap: CGEventTapLocation? = nil) throws {\n        try up(keys: keys, tap: tap)\n    }\n\n    func press(keys: [Key], tap: CGEventTapLocation? = nil) throws {\n        try lock.withLock {\n            for key in keys {\n                try postKeyLocked(key, keyDown: true, tap: tap)\n            }\n            for key in keys.reversed() {\n                try postKeyLocked(key, keyDown: false, tap: tap)\n            }\n        }\n    }\n\n    func press(_ keys: Key..., tap: CGEventTapLocation? = nil) throws {\n        try press(keys: keys, tap: tap)\n    }\n\n    func modifiedCGEventFlags(of event: CGEvent) -> CGEventFlags? {\n        lock.withLock {\n            guard !flags.isEmpty else {\n                return nil\n            }\n\n            guard event.type == .keyDown || event.type == .keyUp else {\n                return nil\n            }\n\n            return event.flags.union(flags)\n        }\n    }\n}\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKit/SymbolicHotKey.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport CoreFoundation\nimport KeyKitC\n\npublic enum SymbolicHotKey: UInt32 {\n    /// full keyboard access hotkeys\n    case toggleFullKeyboardAccess = 12,\n         focusMenubar = 7,\n         focusDock = 8,\n         focusNextGlobalWindow = 9,\n         focusToolbar = 10,\n         focusFloatingWindow = 11,\n         focusApplicationWindow = 27,\n         focusNextControl = 13,\n         focusDrawer = 51,\n         focusStatusItems = 57,\n\n         // screenshot hotkeys\n         screenshot = 28,\n         screenshotToClipboard = 29,\n         screenshotRegion = 30,\n         screenshotRegionToClipboard = 31,\n\n         // universal access\n         toggleZoom = 15,\n         zoomOut = 19,\n         zoomIn = 17,\n         zoomToggleSmoothing = 23,\n         increaseContrast = 25,\n         decreaseContrast = 26,\n         invertScreen = 21,\n         toggleVoiceOver = 59,\n\n         // Dock\n         toggleDockAutohide = 52,\n         exposeAllWindows = 32,\n         exposeAllWindowsSlow = 34,\n         exposeApplicationWindows = 33,\n         exposeApplicationWindowsSlow = 35,\n         exposeDesktop = 36,\n         exposeDesktopsSlow = 37,\n         dashboard = 62,\n         dashboardSlow = 63,\n\n         // spaces (Leopard and later)\n         spaces = 75,\n         spacesSlow = 76,\n         // 77 - fn F7 (disabled)\n         // 78 - ⇧fn F7 (disabled)\n         spaceLeft = 79,\n         spaceLeftSlow = 80,\n         spaceRight = 81,\n         spaceRightSlow = 82,\n         spaceDown = 83,\n         spaceDownSlow = 84,\n         spaceUp = 85,\n         spaceUpSlow = 86,\n\n         // input\n         toggleCharacterPallette = 50,\n         selectPreviousInputSource = 60,\n         selectNextInputSource = 61,\n\n         // Spotlight\n         spotlightSearchField = 64,\n         spotlightWindow = 65,\n\n         toggleFrontRow = 73,\n         lookUpWordInDictionary = 70,\n         help = 98,\n\n         // displays - not verified\n         decreaseDisplayBrightness = 53,\n         increaseDisplayBrightness = 54\n}\n\npublic enum CGSError: Error {\n    case CoreGraphicsError(CGError)\n}\n\npublic func postSymbolicHotKey(_ hotkey: SymbolicHotKey) throws {\n    let hotkey = CGSSymbolicHotKey(hotkey.rawValue)\n\n    var keyEquivalent: unichar = 0\n    var virtualKeyCode: unichar = 0\n    var modifiers = CGSModifierFlags(0)\n\n    let error = CGSGetSymbolicHotKeyValue(\n        hotkey,\n        &keyEquivalent,\n        &virtualKeyCode,\n        &modifiers\n    )\n    guard error == .success else {\n        throw CGSError.CoreGraphicsError(error)\n    }\n\n    let hotkeyEnabled = CGSIsSymbolicHotKeyEnabled(hotkey)\n    if !hotkeyEnabled {\n        CGSSetSymbolicHotKeyEnabled(hotkey, true)\n    }\n    defer {\n        if !hotkeyEnabled {\n            waitUntilCGEventsBeingHandled()\n            CGSSetSymbolicHotKeyEnabled(hotkey, false)\n        }\n    }\n\n    let flags = CGEventFlags(rawValue: UInt64(modifiers.rawValue))\n    let modifierKeyCodes: [(CGEventFlags, CGKeyCode)] = [\n        (.maskShift, 0x38), // kVK_Shift\n        (.maskControl, 0x3B), // kVK_Control\n        (.maskAlternate, 0x3A), // kVK_Option\n        (.maskCommand, 0x37) // kVK_Command\n    ]\n    let activeModifiers = modifierKeyCodes.filter { flags.contains($0.0) }\n\n    // Bookend the synthetic hotkey with explicit `flagsChanged` events that mirror a real\n    // keyboard: the kernel's global modifier state would otherwise remain \"held\" after we\n    // post a key event whose `flags` field includes a modifier (e.g. Control sticks until\n    // a real keystroke clears it).\n    var accumulated = CGEventFlags()\n    for (flag, keyCode) in activeModifiers {\n        accumulated.insert(flag)\n        let event = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: true)!\n        event.type = .flagsChanged\n        event.flags = accumulated\n        event.post(tap: .cgSessionEventTap)\n    }\n\n    let keyDown = CGEvent(keyboardEventSource: nil, virtualKey: virtualKeyCode, keyDown: true)!\n    keyDown.flags = flags\n    let keyUp = CGEvent(keyboardEventSource: nil, virtualKey: virtualKeyCode, keyDown: false)!\n    keyUp.flags = flags\n\n    keyDown.post(tap: .cgSessionEventTap)\n    keyUp.post(tap: .cgSessionEventTap)\n\n    for (flag, keyCode) in activeModifiers.reversed() {\n        accumulated.remove(flag)\n        let event = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: false)!\n        event.type = .flagsChanged\n        event.flags = accumulated\n        event.post(tap: .cgSessionEventTap)\n    }\n}\n\nprivate func waitUntilCGEventsBeingHandled() {\n    enum Consts {\n        static let magic: Int64 = 10_086\n    }\n\n    var seenMark = false\n\n    let callback: CGEventTapCallBack = { _, _, event, refcon in\n        if event.getIntegerValueField(.eventSourceUserData) == Consts.magic {\n            refcon?.storeBytes(of: true, as: Bool.self)\n        }\n\n        return Unmanaged.passUnretained(event)\n    }\n\n    let eventTap = CGEvent.tapCreate(\n        tap: .cgSessionEventTap,\n        place: .tailAppendEventTap,\n        options: .listenOnly,\n        eventsOfInterest: 1 << CGEventType.null.rawValue,\n        callback: callback,\n        userInfo: &seenMark\n    )!\n\n    let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)\n\n    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)\n\n    let mark = CGEvent(source: nil)!\n    mark.setIntegerValueField(.eventSourceUserData, value: Consts.magic)\n    mark.post(tap: .cgSessionEventTap)\n    CGEvent.tapEnable(tap: eventTap, enable: true)\n\n    for _ in 0 ..< 10 {\n        CFRunLoopRunInMode(.defaultMode, 0.01, true)\n        if seenMark {\n            break\n        }\n    }\n\n    CGEvent.tapEnable(tap: eventTap, enable: false)\n\n    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)\n}\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKit/SystemDefinedKey.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport AppKit\nimport Foundation\n\n/// See NX_KEYTYPE_SOUND_UP\npublic enum SystemDefinedKey: Int {\n    case soundUp = 0,\n         soundDown,\n         brightnessUp,\n         brightnessDown,\n         capsLock,\n         help = 5,\n         power,\n         mute,\n         arrowUp,\n         arrowDown,\n         numLock = 10,\n         contrastUp,\n         contrastDown,\n         launchPanel,\n         eject,\n         vidmirror = 15,\n         play,\n         next,\n         previous,\n         fast,\n         rewind = 20,\n         illuminationUp,\n         illuminationDown,\n         illuminationToggle\n}\n\npublic func postSystemDefinedKey(_ key: SystemDefinedKey, keyDown: Bool) {\n    var iter: mach_port_t = 0\n\n    guard IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass), &iter) ==\n        KERN_SUCCESS else {\n        return\n    }\n    defer { IOObjectRelease(iter) }\n\n    let service = IOIteratorNext(iter)\n    guard service != 0 else {\n        return\n    }\n    defer { IOObjectRelease(service) }\n\n    var handle: io_connect_t = .zero\n    guard IOServiceOpen(service, mach_task_self_, UInt32(kIOHIDParamConnectType), &handle) == KERN_SUCCESS else {\n        return\n    }\n    defer { IOServiceClose(handle) }\n\n    var event = NXEventData()\n    event.compound.subType = Int16(NX_SUBTYPE_AUX_CONTROL_BUTTONS)\n    event.compound.misc.L.0 = Int32(key.rawValue) << 16 | (keyDown ? NX_KEYDOWN : NX_KEYUP) << 8\n    IOHIDPostEvent(\n        handle,\n        UInt32(NX_SYSDEFINED),\n        .init(x: 0, y: 0),\n        &event,\n        UInt32(kNXEventDataVersion),\n        IOOptionBits(0),\n        IOOptionBits(kIOHIDSetGlobalEventFlags)\n    )\n}\n\npublic func postSystemDefinedKey(_ key: SystemDefinedKey) {\n    postSystemDefinedKey(key, keyDown: true)\n    postSystemDefinedKey(key, keyDown: false)\n}\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSAccessibility.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_ACCESSIBILITY_INTERNAL_H\n#define CGS_ACCESSIBILITY_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\n\n#pragma mark - Display Zoom\n\n\n/// Gets whether the display is zoomed.\nCG_EXTERN CGError CGSIsZoomed(CGSConnectionID cid, bool *outIsZoomed);\n\n\n#pragma mark - Invert Colors\n\n\n/// Gets the preference value for inverted colors on the current display.\nCG_EXTERN bool CGDisplayUsesInvertedPolarity(void);\n\n/// Sets the preference value for the state of the inverted colors on the current display.  This\n/// preference value is monitored by the system, and updating it causes a fairly immediate change\n/// in the screen's colors.\n///\n/// Internally, this sets and synchronizes `DisplayUseInvertedPolarity` in the\n/// \"com.apple.CoreGraphics\" preferences bundle.\nCG_EXTERN void CGDisplaySetInvertedPolarity(bool invertedPolarity);\n\n\n#pragma mark - Use Grayscale\n\n\n/// Gets whether the screen forces all drawing as grayscale.\nCG_EXTERN bool CGDisplayUsesForceToGray(void);\n\n/// Sets whether the screen forces all drawing as grayscale.\nCG_EXTERN void CGDisplayForceToGray(bool forceToGray);\n\n\n#pragma mark - Increase Contrast\n\n\n/// Sets the display's contrast. There doesn't seem to be a get version of this function.\nCG_EXTERN CGError CGSSetDisplayContrast(CGFloat contrast);\n\n#endif /* CGS_ACCESSIBILITY_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSCIFilter.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_CIFILTER_INTERNAL_H\n#define CGS_CIFILTER_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\ntypedef enum {\n\tkCGWindowFilterUnderlay\t\t= 1,\n\tkCGWindowFilterDock\t\t\t= 0x3001,\n} CGSCIFilterID;\n\n/// Creates a new filter from a filter name.\n///\n/// Any valid CIFilter names are valid names for this function.\nCG_EXTERN CGError CGSNewCIFilterByName(CGSConnectionID cid, CFStringRef filterName, CGSCIFilterID *outFilter);\n\n/// Inserts the given filter into the window.\n///\n/// The values for the `flags` field is currently unknown.\nCG_EXTERN CGError CGSAddWindowFilter(CGSConnectionID cid, CGWindowID wid, CGSCIFilterID filter, int flags);\n\n/// Removes the given filter from the window.\nCG_EXTERN CGError CGSRemoveWindowFilter(CGSConnectionID cid, CGWindowID wid, CGSCIFilterID filter);\n\n/// Invokes `-[CIFilter setValue:forKey:]` on each entry in the dictionary for the window's filter.\n///\n/// The Window Server only checks for the existence of\n///\n///    inputPhase\n///    inputPhase0\n///    inputPhase1\nCG_EXTERN CGError CGSSetCIFilterValuesFromDictionary(CGSConnectionID cid, CGSCIFilterID filter, CFDictionaryRef filterValues);\n\n/// Releases a window's CIFilter.\nCG_EXTERN CGError CGSReleaseCIFilter(CGSConnectionID cid, CGSCIFilterID filter);\n\n#endif /* CGS_CIFILTER_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSConnection.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_CONNECTION_INTERNAL_H\n#define CGS_CONNECTION_INTERNAL_H\n\n/// The type of connections to the Window Server.\n///\n/// Every application is given a singular connection ID through which it can receieve and manipulate\n/// values, state, notifications, events, etc. in the Window Server.  It\ntypedef int CGSConnectionID;\n\ntypedef void *CGSNotificationData;\ntypedef void *CGSNotificationArg;\ntypedef int CGSTransitionID;\n\n\n#pragma mark - Connection Lifecycle\n\n\n/// Gets the default connection for this process.\nCG_EXTERN CGSConnectionID CGSMainConnectionID(void);\n\n/// Creates a new connection to the Window Server.\nCG_EXTERN CGError CGSNewConnection(int unused, CGSConnectionID *outConnection);\n\n/// Releases a CGSConnection and all CGSWindows owned by it.\nCG_EXTERN CGError CGSReleaseConnection(CGSConnectionID cid);\n\n/// Gets the default connection for the current thread.\nCG_EXTERN CGSConnectionID CGSDefaultConnectionForThread(void);\n\n/// Gets the pid of the process that owns this connection to the Window Server.\nCG_EXTERN CGError CGSConnectionGetPID(CGSConnectionID cid, pid_t *outPID);\n\n/// Gets the connection for the given process serial number.\nCG_EXTERN CGError CGSGetConnectionIDForPSN(CGSConnectionID cid, const ProcessSerialNumber *psn, CGSConnectionID *outOwnerCID);\n\n/// Returns whether the menu bar exists for the given connection ID.\n///\n/// For the majority of applications, this function should return true.  But at system updates,\n/// initialization, and shutdown, the menu bar will be either initially gone then created or\n/// hidden and then destroyed.\nCG_EXTERN bool CGSMenuBarExists(CGSConnectionID cid);\n\n/// Closes ALL connections to the Window Server by the current application.\n///\n/// The application is effectively turned into a Console-based application after the invocation of\n/// this method.\nCG_EXTERN CGError CGSShutdownServerConnections(void);\n\n\n#pragma mark - Connection Properties\n\n\n/// Retrieves the value associated with the given key for the given connection.\n///\n/// This method is structured so processes can send values through the Window Server to other\n/// processes - assuming they know each others connection IDs.  The recommended use case for this\n/// function appears to be keeping state around for application-level sub-connections.\nCG_EXTERN CGError CGSCopyConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef *outValue);\n\n/// Associates a value for the given key on the given connection.\nCG_EXTERN CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);\n\n\n#pragma mark - Connection Updates\n\n\n/// Disables updates on a connection\n///\n/// Calls to disable updates nest much like `-beginUpdates`/`-endUpdates`.  the Window Server will\n/// forcibly reenable updates after 1 second if you fail to invoke `CGSReenableUpdate`.\nCG_EXTERN CGError CGSDisableUpdate(CGSConnectionID cid);\n\n/// Re-enables updates on a connection.\n///\n/// Calls to enable updates nest much like `-beginUpdates`/`-endUpdates`.\nCG_EXTERN CGError CGSReenableUpdate(CGSConnectionID cid);\n\n\n#pragma mark - Connection Notifications\n\n\ntypedef void (*CGSNewConnectionNotificationProc)(CGSConnectionID cid);\n\n/// Registers a function that gets invoked when the application's connection ID is created by the\n/// Window Server.\nCG_EXTERN CGError CGSRegisterForNewConnectionNotification(CGSNewConnectionNotificationProc proc);\n\n/// Removes a function that was registered to receive notifications for the creation of the\n/// application's connection to the Window Server.\nCG_EXTERN CGError CGSRemoveNewConnectionNotification(CGSNewConnectionNotificationProc proc);\n\ntypedef void (*CGSConnectionDeathNotificationProc)(CGSConnectionID cid);\n\n/// Registers a function that gets invoked when the application's connection ID is destroyed -\n/// ideally by the Window Server.\n///\n/// Connection death is supposed to be a fatal event that is only triggered when the application\n/// terminates or when you have explicitly destroyed a sub-connection to the Window Server.\nCG_EXTERN CGError CGSRegisterForConnectionDeathNotification(CGSConnectionDeathNotificationProc proc);\n\n/// Removes a function that was registered to receive notifications for the destruction of the\n/// application's connection to the Window Server.\nCG_EXTERN CGError CGSRemoveConnectionDeathNotification(CGSConnectionDeathNotificationProc proc);\n\n\n#pragma mark - Miscellaneous Security Holes\n\n/// Sets a \"Universal Owner\" for the connection ID.  Currently, that owner is Dock.app, which needs\n/// control over the window to provide system features like hiding and showing windows, moving them\n/// around, etc.\n///\n/// Because the Universal Owner owns every window under this connection, it can manipulate them\n/// all as it sees fit.  If you can beat the dock, you have total control over the process'\n/// connection.\nCG_EXTERN CGError CGSSetUniversalOwner(CGSConnectionID cid);\n\n/// Assuming you have the connection ID of the current universal owner, or are said universal owner,\n/// allows you to specify another connection that has total control over the application's windows.\nCG_EXTERN CGError CGSSetOtherUniversalConnection(CGSConnectionID cid, CGSConnectionID otherConnection);\n\n/// Sets the given connection ID as the login window connection ID.  Windows for the application are\n/// then brought to the fore when the computer logs off or goes to sleep.\n///\n/// Why this is still here, I have no idea.  Window Server only accepts one process calling this\n/// ever.  If you attempt to invoke this after loginwindow does you will be yelled at and nothing\n/// will happen.  If you can manage to beat loginwindow, however, you know what they say:\n///\n///    When you teach a man to phish...\nCG_EXTERN CGError CGSSetLoginwindowConnection(CGSConnectionID cid) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;\n\n//! The data sent with kCGSNotificationAppUnresponsive and kCGSNotificationAppResponsive.\ntypedef struct {\n#if __BIG_ENDIAN__\n\tuint16_t majorVersion;\n\tuint16_t minorVersion;\n#else\n\tuint16_t minorVersion;\n\tuint16_t majorVersion;\n#endif\n\n\t//! The length of the entire notification.\n\tuint32_t length;\n\n\tCGSConnectionID cid;\n\tpid_t pid;\n\tProcessSerialNumber psn;\n} CGSProcessNotificationData;\n\n//! The data sent with kCGSNotificationDebugOptionsChanged.\ntypedef struct {\n\tint newOptions;\n\tint unknown[2]; // these two seem to be zero\n} CGSDebugNotificationData;\n\n//! The data sent with kCGSNotificationTransitionEnded\ntypedef struct {\n\tCGSTransitionID transition;\n} CGSTransitionNotificationData;\n\n#endif /* CGS_CONNECTION_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSCursor.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_CURSOR_INTERNAL_H\n#define CGS_CURSOR_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\ntypedef enum : NSInteger {\n\tCGSCursorArrow\t\t\t= 0,\n\tCGSCursorIBeam\t\t\t= 1,\n\tCGSCursorIBeamXOR\t\t= 2,\n\tCGSCursorAlias\t\t\t= 3,\n\tCGSCursorCopy\t\t\t= 4,\n\tCGSCursorMove\t\t\t= 5,\n\tCGSCursorArrowContext\t= 6,\n\tCGSCursorWait\t\t\t= 7,\n\tCGSCursorEmpty\t\t\t= 8,\n} CGSCursorID;\n\n\n/// Registers a cursor with the given properties.\n///\n/// - Parameter cid:\t\t\tThe connection ID to register with.\n/// - Parameter cursorName:\t\tThe system-wide name the cursor will be registered under.\n/// - Parameter setGlobally:\tWhether the cursor registration can appear system-wide.\n/// - Parameter instantly:\t\tWhether the registration of cursor images should occur immediately.  Passing false\n///                             may speed up the call.\n/// - Parameter frameCount:     The number of images in the cursor image array.\n/// - Parameter imageArray:     An array of CGImageRefs that are used to display the cursor.  Multiple images in\n///                             conjunction with a non-zero `frameDuration` cause animation.\n/// - Parameter cursorSize:     The size of the cursor's images.  Recommended size is 16x16 points\n/// - Parameter hotspot:\t\tThe location touch events will emanate from.\n/// - Parameter seed:\t\t\tThe seed for the cursor's registration.\n/// - Parameter bounds:\t\t\tThe total size of the cursor.\n/// - Parameter frameDuration:\tHow long each image will be displayed for.\n/// - Parameter repeatCount:\tNumber of times the cursor should repeat cycling its image frames.\nCG_EXTERN CGError CGSRegisterCursorWithImages(CGSConnectionID cid,\n\t\t\t\t\t\t\t\t\t\t\t  const char *cursorName,\n\t\t\t\t\t\t\t\t\t\t\t  bool setGlobally, bool instantly,\n\t\t\t\t\t\t\t\t\t\t\t  NSUInteger frameCount, CFArrayRef imageArray,\n\t\t\t\t\t\t\t\t\t\t\t  CGSize cursorSize, CGPoint hotspot,\n\t\t\t\t\t\t\t\t\t\t\t  int *seed,\n\t\t\t\t\t\t\t\t\t\t\t  CGRect bounds, CGFloat frameDuration,\n\t\t\t\t\t\t\t\t\t\t\t  NSInteger repeatCount);\n\n\n#pragma mark - Cursor Registration\n\n\n/// Copies the size of data associated with the cursor registered under the given name.\nCG_EXTERN CGError CGSGetRegisteredCursorDataSize(CGSConnectionID cid, const char *cursorName, size_t *outDataSize);\n\n/// Re-assigns the given cursor name to the cursor represented by the given seed value.\nCG_EXTERN CGError CGSSetRegisteredCursor(CGSConnectionID cid, const char *cursorName, int *cursorSeed);\n\n/// Copies the properties out of the cursor registered under the given name.\nCG_EXTERN CGError CGSCopyRegisteredCursorImages(CGSConnectionID cid, const char *cursorName, CGSize *imageSize, CGPoint *hotSpot, NSUInteger *frameCount, CGFloat *frameDuration, CFArrayRef *imageArray);\n\n/// Re-assigns one of the system-defined cursors to the cursor represented by the given seed value.\nCG_EXTERN void CGSSetSystemDefinedCursorWithSeed(CGSConnectionID connection, CGSCursorID systemCursor, int *cursorSeed);\n\n\n#pragma mark - Cursor Display\n\n\n/// Shows the cursor.\nCG_EXTERN CGError CGSShowCursor(CGSConnectionID cid);\n\n/// Hides the cursor.\nCG_EXTERN CGError CGSHideCursor(CGSConnectionID cid);\n\n/// Hides the cursor until the cursor is moved.\nCG_EXTERN CGError CGSObscureCursor(CGSConnectionID cid);\n\n/// Acts as if a mouse moved event occured and that reveals the cursor if it was hidden.\nCG_EXTERN CGError CGSRevealCursor(CGSConnectionID cid);\n\n/// Shows or hides the spinning beachball of death.\n///\n/// If you call this, I hate you.\nCG_EXTERN CGError CGSForceWaitCursorActive(CGSConnectionID cid, bool showWaitCursor);\n\n/// Unconditionally sets the location of the cursor on the screen to the given coordinates.\nCG_EXTERN CGError CGSWarpCursorPosition(CGSConnectionID cid, CGFloat x, CGFloat y);\n\n\n#pragma mark - Cursor Properties\n\n\n/// Gets the current cursor's seed value.\n///\n/// Every time the cursor is updated, the seed changes.\nCG_EXTERN int CGSCurrentCursorSeed(void);\n\n/// Gets the current location of the cursor relative to the screen's coordinates.\nCG_EXTERN CGError CGSGetCurrentCursorLocation(CGSConnectionID cid, CGPoint *outPos);\n\n/// Gets the name (ideally in reverse DNS form) of a system cursor.\nCG_EXTERN char *CGSCursorNameForSystemCursor(CGSCursorID cursor);\n\n/// Gets the scale of the current currsor.\nCG_EXTERN CGError CGSGetCursorScale(CGSConnectionID cid, CGFloat *outScale);\n\n/// Sets the scale of the current cursor.\n///\n/// The largest the Universal Access prefpane allows you to go is 4.0.\nCG_EXTERN CGError CGSSetCursorScale(CGSConnectionID cid, CGFloat scale);\n\n\n#pragma mark - Cursor Data\n\n\n/// Gets the size of the data for the connection's cursor.\nCG_EXTERN CGError CGSGetCursorDataSize(CGSConnectionID cid, size_t *outDataSize);\n\n/// Gets the data for the connection's cursor.\nCG_EXTERN CGError CGSGetCursorData(CGSConnectionID cid, void *outData);\n\n/// Gets the size of the data for the current cursor.\nCG_EXTERN CGError CGSGetGlobalCursorDataSize(CGSConnectionID cid, size_t *outDataSize);\n\n/// Gets the data for the current cursor.\nCG_EXTERN CGError CGSGetGlobalCursorData(CGSConnectionID cid, void *outData, int *outDataSize, int *outRowBytes, CGRect *outRect, CGPoint *outHotSpot, int *outDepth, int *outComponents, int *outBitsPerComponent);\n\n/// Gets the size of data for a system-defined cursor.\nCG_EXTERN CGError CGSGetSystemDefinedCursorDataSize(CGSConnectionID cid, CGSCursorID cursor, size_t *outDataSize);\n\n/// Gets the data for a system-defined cursor.\nCG_EXTERN CGError CGSGetSystemDefinedCursorData(CGSConnectionID cid, CGSCursorID cursor, void *outData, int *outRowBytes, CGRect *outRect, CGPoint *outHotSpot, int *outDepth, int *outComponents, int *outBitsPerComponent);\n\n#endif /* CGS_CURSOR_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSDebug.h",
    "content": "/*\n * Routines for debugging the Window Server and application drawing.\n *\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_DEBUG_INTERNAL_H\n#define CGS_DEBUG_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\n/// The set of options that the Window Server\ntypedef enum {\n\t/// Clears all flags.\n\tkCGSDebugOptionNone\t\t\t\t\t\t\t= 0,\n\n\t/// All screen updates are flashed in yellow. Regions under a DisableUpdate are flashed in orange. Regions that are hardware accellerated are painted green.\n\tkCGSDebugOptionFlashScreenUpdates\t\t\t= 0x4,\n\n\t/// Colors windows green if they are accellerated, otherwise red. Doesn't cause things to refresh properly - leaves excess rects cluttering the screen.\n\tkCGSDebugOptionColorByAccelleration\t\t\t= 0x20,\n\n\t/// Disables shadows on all windows.\n\tkCGSDebugOptionNoShadows\t\t\t\t\t= 0x4000,\n\n\t/// Setting this disables the pause after a flash when using FlashScreenUpdates or FlashIdenticalUpdates.\n\tkCGSDebugOptionNoDelayAfterFlash\t\t\t= 0x20000,\n\n\t/// Flushes the contents to the screen after every drawing operation.\n\tkCGSDebugOptionAutoflushDrawing\t\t\t\t= 0x40000,\n\n\t/// Highlights mouse tracking areas. Doesn't cause things to refresh correctly - leaves excess rectangles cluttering the screen.\n\tkCGSDebugOptionShowMouseTrackingAreas\t\t= 0x100000,\n\n\t/// Flashes identical updates in red.\n\tkCGSDebugOptionFlashIdenticalUpdates\t\t= 0x4000000,\n\n\t/// Dumps a list of windows to /tmp/WindowServer.winfo.out. This is what Quartz Debug uses to get the window list.\n\tkCGSDebugOptionDumpWindowListToFile\t\t\t= 0x80000001,\n\n\t/// Dumps a list of connections to /tmp/WindowServer.cinfo.out.\n\tkCGSDebugOptionDumpConnectionListToFile\t\t= 0x80000002,\n\n\t/// Dumps a very verbose debug log of the WindowServer to /tmp/CGLog_WinServer_<PID>.\n\tkCGSDebugOptionVerboseLogging\t\t\t\t= 0x80000006,\n\n\t/// Dumps a very verbose debug log of all processes to /tmp/CGLog_<NAME>_<PID>.\n\tkCGSDebugOptionVerboseLoggingAllApps\t\t= 0x80000007,\n\n\t/// Dumps a list of hotkeys to /tmp/WindowServer.keyinfo.out.\n\tkCGSDebugOptionDumpHotKeyListToFile\t\t\t= 0x8000000E,\n\n\t/// Dumps information about OpenGL extensions, etc to /tmp/WindowServer.glinfo.out.\n\tkCGSDebugOptionDumpOpenGLInfoToFile\t\t\t= 0x80000013,\n\n\t/// Dumps a list of shadows to /tmp/WindowServer.shinfo.out.\n\tkCGSDebugOptionDumpShadowListToFile\t\t\t= 0x80000014,\n\n\t/// Leopard: Dumps information about caches to `/tmp/WindowServer.scinfo.out`.\n\tkCGSDebugOptionDumpCacheInformationToFile\t= 0x80000015,\n\n\t/// Leopard: Purges some sort of cache - most likely the same caches dummped with `kCGSDebugOptionDumpCacheInformationToFile`.\n\tkCGSDebugOptionPurgeCaches\t\t\t\t\t= 0x80000016,\n\n\t/// Leopard: Dumps a list of windows to `/tmp/WindowServer.winfo.plist`. This is what Quartz Debug on 10.5 uses to get the window list.\n\tkCGSDebugOptionDumpWindowListToPlist\t\t= 0x80000017,\n\n\t/// Leopard: DOCUMENTATION PENDING\n\tkCGSDebugOptionEnableSurfacePurging\t\t\t= 0x8000001B,\n\n\t// Leopard: 0x8000001C - invalid\n\n\t/// Leopard: DOCUMENTATION PENDING\n\tkCGSDebugOptionDisableSurfacePurging\t\t= 0x8000001D,\n\n\t/// Leopard: Dumps information about an application's resource usage to `/tmp/CGResources_<NAME>_<PID>`.\n\tkCGSDebugOptionDumpResourceUsageToFiles\t\t= 0x80000020,\n\n\t// Leopard: 0x80000022 - something about QuartzGL?\n\n\t// Leopard: Returns the magic mirror to its normal mode. The magic mirror is what the Dock uses to draw the screen reflection. For more information, see `CGSSetMagicMirror`.\n\tkCGSDebugOptionSetMagicMirrorModeNormal\t\t= 0x80000023,\n\n\t/// Leopard: Disables the magic mirror. It still appears but draws black instead of a reflection.\n\tkCGSDebugOptionSetMagicMirrorModeDisabled\t= 0x80000024,\n} CGSDebugOption;\n\n\n/// Gets and sets the debug options.\n///\n/// These options are global and are not reset when your application dies!\nCG_EXTERN CGError CGSGetDebugOptions(int *outCurrentOptions);\nCG_EXTERN CGError CGSSetDebugOptions(int options);\n\n/// Queries the server about its performance. This is how Quartz Debug gets the FPS meter, but not\n/// the CPU meter (for that it uses host_processor_info). Quartz Debug subtracts 25 so that it is at\n/// zero with the minimum FPS.\nCG_EXTERN CGError CGSGetPerformanceData(CGSConnectionID cid, CGFloat *outFPS, CGFloat *unk, CGFloat *unk2, CGFloat *unk3);\n\n#endif /* CGS_DEBUG_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSDevice.h",
    "content": "//\n//  CGSDevice.h\n//  CGSInternal\n//\n//  Created by Robert Widmann on 9/14/13.\n//  Copyright (c) 2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n\n#ifndef CGS_DEVICE_INTERNAL_H\n#define CGS_DEVICE_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\n/// Actuates the Taptic Engine underneath the user's fingers.\n///\n/// Valid patterns are in the range 0x1-0x6 and 0xf-0x10 inclusive.\n///\n/// Currently, deviceID and strength must be 0 as non-zero configurations are not\n/// yet supported\nCG_EXTERN CGError CGSActuateDeviceWithPattern(CGSConnectionID cid, int deviceID, int pattern, int strength) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n/// Overrides the current pressure configuration with the given configuration.\nCG_EXTERN CGError CGSSetPressureConfigurationOverride(CGSConnectionID cid, int deviceID, void *config) AVAILABLE_MAC_OS_X_VERSION_10_10_3_AND_LATER;\n\n#endif /* CGSDevice_h */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSDisplays.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n * Ryan Govostes ryan@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_DISPLAYS_INTERNAL_H\n#define CGS_DISPLAYS_INTERNAL_H\n\n#include \"CGSRegion.h\"\n\ntypedef enum {\n\tCGSDisplayQueryMirrorStatus = 9,\n} CGSDisplayQuery;\n\ntypedef struct {\n\tuint32_t mode;\n\tuint32_t flags;\n\tuint32_t width;\n\tuint32_t height;\n\tuint32_t depth;\n\tuint32_t dc2[42];\n\tuint16_t dc3;\n\tuint16_t freq;\n\tuint8_t dc4[16];\n\tCGFloat scale;\n} CGSDisplayModeDescription;\n\ntypedef int CGSDisplayMode;\n\n\n/// Gets the main display.\nCG_EXTERN CGDirectDisplayID CGSMainDisplayID(void);\n\n\n#pragma mark - Display Properties\n\n\n/// Gets the number of displays known to the system.\nCG_EXTERN uint32_t CGSGetNumberOfDisplays(void);\n\n/// Gets the depth of a display.\nCG_EXTERN CGError CGSGetDisplayDepth(CGDirectDisplayID display, int *outDepth);\n\n/// Gets the displays at a point. Note that multiple displays can have the same point - think mirroring.\nCG_EXTERN CGError CGSGetDisplaysWithPoint(const CGPoint *point, int maxDisplayCount, CGDirectDisplayID *outDisplays, int *outDisplayCount);\n\n/// Gets the displays which contain a rect. Note that multiple displays can have the same bounds - think mirroring.\nCG_EXTERN CGError CGSGetDisplaysWithRect(const CGRect *point, int maxDisplayCount, CGDirectDisplayID *outDisplays, int *outDisplayCount);\n\n/// Gets the bounds for the display. Note that multiple displays can have the same bounds - think mirroring.\nCG_EXTERN CGError CGSGetDisplayRegion(CGDirectDisplayID display, CGSRegionRef *outRegion);\nCG_EXTERN CGError CGSGetDisplayBounds(CGDirectDisplayID display, CGRect *outRect);\n\n/// Gets the number of bytes per row.\nCG_EXTERN CGError CGSGetDisplayRowBytes(CGDirectDisplayID display, int *outRowBytes);\n\n/// Returns an array of dictionaries describing the spaces each screen contains.\nCG_EXTERN CFArrayRef CGSCopyManagedDisplaySpaces(CGSConnectionID cid);\n\n/// Gets the current display mode for the display.\nCG_EXTERN CGError CGSGetCurrentDisplayMode(CGDirectDisplayID display, int *modeNum);\n\n/// Gets the number of possible display modes for the display.\nCG_EXTERN CGError CGSGetNumberOfDisplayModes(CGDirectDisplayID display, int *nModes);\n\n/// Gets a description of the mode of the display.\nCG_EXTERN CGError CGSGetDisplayModeDescriptionOfLength(CGDirectDisplayID display, int idx, CGSDisplayModeDescription *desc, int length);\n\n/// Sets a display's configuration mode.\nCG_EXTERN CGError CGSConfigureDisplayMode(CGDisplayConfigRef config, CGDirectDisplayID display, int modeNum);\n\n/// Gets a list of on line displays */\nCG_EXTERN CGDisplayErr CGSGetOnlineDisplayList(CGDisplayCount maxDisplays, CGDirectDisplayID *displays, CGDisplayCount *outDisplayCount);\n\n/// Gets a list of active displays */\nCG_EXTERN CGDisplayErr CGSGetActiveDisplayList(CGDisplayCount maxDisplays, CGDirectDisplayID *displays, CGDisplayCount *outDisplayCount);\n\n\n#pragma mark - Display Configuration\n\n\n/// Begins a new display configuration transacation.\nCG_EXTERN CGDisplayErr CGSBeginDisplayConfiguration(CGDisplayConfigRef *config);\n\n/// Sets the origin of a display relative to the main display. The main display is at (0, 0) and contains the menubar.\nCG_EXTERN CGDisplayErr CGSConfigureDisplayOrigin(CGDisplayConfigRef config, CGDirectDisplayID display, int32_t x, int32_t y);\n\n/// Applies the configuration changes made in this transaction.\nCG_EXTERN CGDisplayErr CGSCompleteDisplayConfiguration(CGDisplayConfigRef config);\n\n/// Drops the configuration changes made in this transaction.\nCG_EXTERN CGDisplayErr CGSCancelDisplayConfiguration(CGDisplayConfigRef config);\n\n\n#pragma mark - Querying for Display Status\n\n\n/// Queries the Window Server about the status of the query.\nCG_EXTERN CGError CGSDisplayStatusQuery(CGDirectDisplayID display, CGSDisplayQuery query);\n\n#endif /* CGS_DISPLAYS_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSEvent.h",
    "content": "//\n//  CGSEvent.h\n//  CGSInternal\n//\n//  Created by Robert Widmann on 9/14/13.\n//  Copyright (c) 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_EVENT_INTERNAL_H\n#define CGS_EVENT_INTERNAL_H\n\n#include \"CGSWindow.h\"\n\ntypedef unsigned long CGSByteCount;\ntypedef unsigned short CGSEventRecordVersion;\ntypedef unsigned long long CGSEventRecordTime;  /* nanosecond timer */\ntypedef unsigned long CGSEventFlag;\ntypedef unsigned long  CGSError;\n\ntypedef enum : unsigned int {\n\tkCGSDisplayWillReconfigure = 100,\n\tkCGSDisplayDidReconfigure = 101,\n\tkCGSDisplayWillSleep = 102,\n\tkCGSDisplayDidWake = 103,\n\tkCGSDisplayIsCaptured = 106,\n\tkCGSDisplayIsReleased = 107,\n\tkCGSDisplayAllDisplaysReleased = 108,\n\tkCGSDisplayHardwareChanged = 111,\n\tkCGSDisplayDidReconfigure2 = 115,\n\tkCGSDisplayFullScreenAppRunning = 116,\n\tkCGSDisplayFullScreenAppDone = 117,\n\tkCGSDisplayReconfigureHappened = 118,\n\tkCGSDisplayColorProfileChanged = 119,\n\tkCGSDisplayZoomStateChanged = 120,\n\tkCGSDisplayAcceleratorChanged = 121,\n\tkCGSDebugOptionsChangedNotification = 200,\n\tkCGSDebugPrintResourcesNotification = 203,\n\tkCGSDebugPrintResourcesMemoryNotification = 205,\n\tkCGSDebugPrintResourcesContextNotification = 206,\n\tkCGSDebugPrintResourcesImageNotification = 208,\n\tkCGSServerConnDirtyScreenNotification = 300,\n\tkCGSServerLoginNotification = 301,\n\tkCGSServerShutdownNotification = 302,\n\tkCGSServerUserPreferencesLoadedNotification = 303,\n\tkCGSServerUpdateDisplayNotification = 304,\n\tkCGSServerCAContextDidCommitNotification = 305,\n\tkCGSServerUpdateDisplayCompletedNotification = 306,\n\n\tkCPXForegroundProcessSwitched = 400,\n\tkCPXSpecialKeyPressed = 401,\n\tkCPXForegroundProcessSwitchRequestedButRedundant = 402,\n\n\tkCGSSpecialKeyEventNotification = 700,\n\n\tkCGSEventNotificationNullEvent = 710,\n\tkCGSEventNotificationLeftMouseDown = 711,\n\tkCGSEventNotificationLeftMouseUp = 712,\n\tkCGSEventNotificationRightMouseDown = 713,\n\tkCGSEventNotificationRightMouseUp = 714,\n\tkCGSEventNotificationMouseMoved = 715,\n\tkCGSEventNotificationLeftMouseDragged = 716,\n\tkCGSEventNotificationRightMouseDragged = 717,\n\tkCGSEventNotificationMouseEntered = 718,\n\tkCGSEventNotificationMouseExited = 719,\n\n\tkCGSEventNotificationKeyDown = 720,\n\tkCGSEventNotificationKeyUp = 721,\n\tkCGSEventNotificationFlagsChanged = 722,\n\tkCGSEventNotificationKitDefined = 723,\n\tkCGSEventNotificationSystemDefined = 724,\n\tkCGSEventNotificationApplicationDefined = 725,\n\tkCGSEventNotificationTimer = 726,\n\tkCGSEventNotificationCursorUpdate = 727,\n\tkCGSEventNotificationSuspend = 729,\n\tkCGSEventNotificationResume = 730,\n\tkCGSEventNotificationNotification = 731,\n\tkCGSEventNotificationScrollWheel = 732,\n\tkCGSEventNotificationTabletPointer = 733,\n\tkCGSEventNotificationTabletProximity = 734,\n\tkCGSEventNotificationOtherMouseDown = 735,\n\tkCGSEventNotificationOtherMouseUp = 736,\n\tkCGSEventNotificationOtherMouseDragged = 737,\n\tkCGSEventNotificationZoom = 738,\n\tkCGSEventNotificationAppIsUnresponsive = 750,\n\tkCGSEventNotificationAppIsNoLongerUnresponsive = 751,\n\n\tkCGSEventSecureTextInputIsActive = 752,\n\tkCGSEventSecureTextInputIsOff = 753,\n\n\tkCGSEventNotificationSymbolicHotKeyChanged = 760,\n\tkCGSEventNotificationSymbolicHotKeyDisabled = 761,\n\tkCGSEventNotificationSymbolicHotKeyEnabled = 762,\n\tkCGSEventNotificationHotKeysGloballyDisabled = 763,\n\tkCGSEventNotificationHotKeysGloballyEnabled = 764,\n\tkCGSEventNotificationHotKeysExceptUniversalAccessGloballyDisabled = 765,\n\tkCGSEventNotificationHotKeysExceptUniversalAccessGloballyEnabled = 766,\n\n\tkCGSWindowIsObscured = 800,\n\tkCGSWindowIsUnobscured = 801,\n\tkCGSWindowIsOrderedIn = 802,\n\tkCGSWindowIsOrderedOut = 803,\n\tkCGSWindowIsTerminated = 804,\n\tkCGSWindowIsChangingScreens = 805,\n\tkCGSWindowDidMove = 806,\n\tkCGSWindowDidResize = 807,\n\tkCGSWindowDidChangeOrder = 808,\n\tkCGSWindowGeometryDidChange = 809,\n\tkCGSWindowMonitorDataPending = 810,\n\tkCGSWindowDidCreate = 811,\n\tkCGSWindowRightsGrantOffered = 812,\n\tkCGSWindowRightsGrantCompleted = 813,\n\tkCGSWindowRecordForTermination = 814,\n\tkCGSWindowIsVisible = 815,\n\tkCGSWindowIsInvisible = 816,\n\n\tkCGSLikelyUnbalancedDisableUpdateNotification = 902,\n\n\tkCGSConnectionWindowsBecameVisible = 904,\n\tkCGSConnectionWindowsBecameOccluded = 905,\n\tkCGSConnectionWindowModificationsStarted = 906,\n\tkCGSConnectionWindowModificationsStopped = 907,\n\n\tkCGSWindowBecameVisible = 912,\n\tkCGSWindowBecameOccluded = 913,\n\n\tkCGSServerWindowDidCreate = 1000,\n\tkCGSServerWindowWillTerminate = 1001,\n\tkCGSServerWindowOrderDidChange = 1002,\n\tkCGSServerWindowDidTerminate = 1003,\n\t\n\tkCGSWindowWasMovedByDockEvent = 1205,\n\tkCGSWindowWasResizedByDockEvent = 1207,\n\tkCGSWindowDidBecomeManagedByDockEvent = 1208,\n\t\n\tkCGSServerMenuBarCreated = 1300,\n\tkCGSServerHidBackstopMenuBar = 1301,\n\tkCGSServerShowBackstopMenuBar = 1302,\n\tkCGSServerMenuBarDrawingStyleChanged = 1303,\n\tkCGSServerPersistentAppsRegistered = 1304,\n\tkCGSServerPersistentCheckinComplete = 1305,\n\n\tkCGSPackagesWorkspacesDisabled = 1306,\n\tkCGSPackagesWorkspacesEnabled = 1307,\n\tkCGSPackagesStatusBarSpaceChanged = 1308,\n\n\tkCGSWorkspaceWillChange = 1400,\n\tkCGSWorkspaceDidChange = 1401,\n\tkCGSWorkspaceWindowIsViewable = 1402,\n\tkCGSWorkspaceWindowIsNotViewable = 1403,\n\tkCGSWorkspaceWindowDidMove = 1404,\n\tkCGSWorkspacePrefsDidChange = 1405,\n\tkCGSWorkspacesWindowDragDidStart = 1411,\n\tkCGSWorkspacesWindowDragDidEnd = 1412,\n\tkCGSWorkspacesWindowDragWillEnd = 1413,\n\tkCGSWorkspacesShowSpaceForProcess = 1414,\n\tkCGSWorkspacesWindowDidOrderInOnNonCurrentManagedSpacesOnly = 1415,\n\tkCGSWorkspacesWindowDidOrderOutOnNonCurrentManagedSpaces = 1416,\n\n\tkCGSessionConsoleConnect = 1500,\n\tkCGSessionConsoleDisconnect = 1501,\n\tkCGSessionRemoteConnect = 1502,\n\tkCGSessionRemoteDisconnect = 1503,\n\tkCGSessionLoggedOn = 1504,\n\tkCGSessionLoggedOff = 1505,\n\tkCGSessionConsoleWillDisconnect = 1506,\n\tkCGXWillCreateSession = 1550,\n\tkCGXDidCreateSession = 1551,\n\tkCGXWillDestroySession = 1552,\n\tkCGXDidDestroySession = 1553,\n\tkCGXWorkspaceConnected = 1554,\n\tkCGXSessionReleased = 1555,\n\n\tkCGSTransitionDidFinish = 1700,\n\n\tkCGXServerDisplayHardwareWillReset = 1800,\n\tkCGXServerDesktopShapeChanged = 1801,\n\tkCGXServerDisplayConfigurationChanged = 1802,\n\tkCGXServerDisplayAcceleratorOffline = 1803,\n\tkCGXServerDisplayAcceleratorDeactivate = 1804,\n} CGSEventType;\n\n\n#pragma mark - System-Level Event Notification Registration\n\n\ntypedef void (*CGSNotifyProcPtr)(CGSEventType type, void *data, unsigned int dataLength, void *userData);\n\n/// Registers a function to receive notifications for system-wide events.\nCG_EXTERN CGError CGSRegisterNotifyProc(CGSNotifyProcPtr proc, CGSEventType type, void *userData);\n\n/// Unregisters a function that was registered to receive notifications for system-wide events.\nCG_EXTERN CGError CGSRemoveNotifyProc(CGSNotifyProcPtr proc, CGSEventType type, void *userData);\n\n\n#pragma mark - Application-Level Event Notification Registration\n\n\ntypedef void (*CGConnectionNotifyProc)(CGSEventType type, CGSNotificationData notificationData, size_t dataLength, CGSNotificationArg userParameter, CGSConnectionID);\n\n/// Registers a function to receive notifications for connection-level events.\nCG_EXTERN CGError CGSRegisterConnectionNotifyProc(CGSConnectionID cid, CGConnectionNotifyProc function, CGSEventType event, void *userData);\n\n/// Unregisters a function that was registered to receive notifications for connection-level events.\nCG_EXTERN CGError CGSRemoveConnectionNotifyProc(CGSConnectionID cid, CGConnectionNotifyProc function, CGSEventType event, void *userData);\n\n\ntypedef struct _CGSEventRecord {\n\tCGSEventRecordVersion major; /*0x0*/\n\tCGSEventRecordVersion minor; /*0x2*/\n\tCGSByteCount length;         /*0x4*/ /* Length of complete event record */\n\tCGSEventType type;           /*0x8*/ /* An event type from above */\n\tCGPoint location;            /*0x10*/ /* Base coordinates (global), from upper-left */\n\tCGPoint windowLocation;      /*0x20*/ /* Coordinates relative to window */\n\tCGSEventRecordTime time;     /*0x30*/ /* nanoseconds since startup */\n\tCGSEventFlag flags;         /* key state flags */\n\tCGWindowID window;         /* window number of assigned window */\n\tCGSConnectionID connection; /* connection the event came from */\n\tstruct __CGEventSourceData {\n\t\tint source;\n\t\tunsigned int sourceUID;\n\t\tunsigned int sourceGID;\n\t\tunsigned int flags;\n\t\tunsigned long long userData;\n\t\tunsigned int sourceState;\n\t\tunsigned short localEventSuppressionInterval;\n\t\tunsigned char suppressionIntervalFlags;\n\t\tunsigned char remoteMouseDragFlags;\n\t\tunsigned long long serviceID;\n\t} eventSource;\n\tstruct _CGEventProcess {\n\t\tint pid;\n\t\tunsigned int psnHi;\n\t\tunsigned int psnLo;\n\t\tunsigned int targetID;\n\t\tunsigned int flags;\n\t} eventProcess;\n\tNXEventData eventData;\n\tSInt32 _padding[4];\n\tvoid *ioEventData;\n\tunsigned short _field16;\n\tunsigned short _field17;\n\tstruct _CGSEventAppendix {\n\t\tunsigned short windowHeight;\n\t\tunsigned short mainDisplayHeight;\n\t\tunsigned short *unicodePayload;\n\t\tunsigned int eventOwner;\n\t\tunsigned char passedThrough;\n\t} *appendix;\n\tunsigned int _field18;\n\tbool passedThrough;\n\tCFDataRef data;\n} CGSEventRecord;\n\n/// Gets the event record for a given `CGEventRef`.\n///\n/// For Carbon events, use `GetEventPlatformEventRecord`.\nCG_EXTERN CGError CGEventGetEventRecord(CGEventRef event, CGSEventRecord *outRecord, size_t recSize);\n\n/// Gets the main event port for the connection ID.\nCG_EXTERN OSErr CGSGetEventPort(CGSConnectionID identifier, mach_port_t *port);\n\n/// Getter and setter for the background event mask.\nCG_EXTERN void CGSGetBackgroundEventMask(CGSConnectionID cid, int *outMask);\nCG_EXTERN CGError CGSSetBackgroundEventMask(CGSConnectionID cid, int mask);\n\n\n/// Returns\t`True` if the application has been deemed unresponsive for a certain amount of time.\nCG_EXTERN bool CGSEventIsAppUnresponsive(CGSConnectionID cid, const ProcessSerialNumber *psn);\n\n/// Sets the amount of time it takes for an application to be considered unresponsive.\nCG_EXTERN CGError CGSEventSetAppIsUnresponsiveNotificationTimeout(CGSConnectionID cid, double theTime);\n\n#pragma mark input\n\n// Gets and sets the status of secure input. When secure input is enabled, keyloggers, etc are harder to do.\nCG_EXTERN bool CGSIsSecureEventInputSet(void);\nCG_EXTERN CGError CGSSetSecureEventInput(CGSConnectionID cid, bool useSecureInput);\n\n#endif /* CGS_EVENT_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSHotKeys.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n *\n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n *\n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n *\n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n *\n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_HOTKEYS_INTERNAL_H\n#define CGS_HOTKEYS_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\n/// The system defines a limited number of \"symbolic\" hot keys that are remembered system-wide.  The\n/// original intent is to have a common registry for the action of function keys and numerous\n/// other event-generating system gestures.\ntypedef enum {\n\t// full keyboard access hotkeys\n\tkCGSHotKeyToggleFullKeyboardAccess = 12,\n\tkCGSHotKeyFocusMenubar = 7,\n\tkCGSHotKeyFocusDock = 8,\n\tkCGSHotKeyFocusNextGlobalWindow = 9,\n\tkCGSHotKeyFocusToolbar = 10,\n\tkCGSHotKeyFocusFloatingWindow = 11,\n\tkCGSHotKeyFocusApplicationWindow = 27,\n\tkCGSHotKeyFocusNextControl = 13,\n\tkCGSHotKeyFocusDrawer = 51,\n\tkCGSHotKeyFocusStatusItems = 57,\n\n\t// screenshot hotkeys\n\tkCGSHotKeyScreenshot = 28,\n\tkCGSHotKeyScreenshotToClipboard = 29,\n\tkCGSHotKeyScreenshotRegion = 30,\n\tkCGSHotKeyScreenshotRegionToClipboard = 31,\n\n\t// universal access\n\tkCGSHotKeyToggleZoom = 15,\n\tkCGSHotKeyZoomOut = 19,\n\tkCGSHotKeyZoomIn = 17,\n\tkCGSHotKeyZoomToggleSmoothing = 23,\n\tkCGSHotKeyIncreaseContrast = 25,\n\tkCGSHotKeyDecreaseContrast = 26,\n\tkCGSHotKeyInvertScreen = 21,\n\tkCGSHotKeyToggleVoiceOver = 59,\n\n\t// Dock\n\tkCGSHotKeyToggleDockAutohide = 52,\n\tkCGSHotKeyExposeAllWindows = 32,\n\tkCGSHotKeyExposeAllWindowsSlow = 34,\n\tkCGSHotKeyExposeApplicationWindows = 33,\n\tkCGSHotKeyExposeApplicationWindowsSlow = 35,\n\tkCGSHotKeyExposeDesktop = 36,\n\tkCGSHotKeyExposeDesktopsSlow = 37,\n\tkCGSHotKeyDashboard = 62,\n\tkCGSHotKeyDashboardSlow = 63,\n\n\t// spaces (Leopard and later)\n\tkCGSHotKeySpaces = 75,\n\tkCGSHotKeySpacesSlow = 76,\n\t// 77 - fn F7 (disabled)\n\t// 78 - ⇧fn F7 (disabled)\n\tkCGSHotKeySpaceLeft = 79,\n\tkCGSHotKeySpaceLeftSlow = 80,\n\tkCGSHotKeySpaceRight = 81,\n\tkCGSHotKeySpaceRightSlow = 82,\n\tkCGSHotKeySpaceDown = 83,\n\tkCGSHotKeySpaceDownSlow = 84,\n\tkCGSHotKeySpaceUp = 85,\n\tkCGSHotKeySpaceUpSlow = 86,\n\n\t// input\n\tkCGSHotKeyToggleCharacterPallette = 50,\n\tkCGSHotKeySelectPreviousInputSource = 60,\n\tkCGSHotKeySelectNextInputSource = 61,\n\n\t// Spotlight\n\tkCGSHotKeySpotlightSearchField = 64,\n\tkCGSHotKeySpotlightWindow = 65,\n\n\tkCGSHotKeyToggleFrontRow = 73,\n\tkCGSHotKeyLookUpWordInDictionary = 70,\n\tkCGSHotKeyHelp = 98,\n\n\t// displays - not verified\n\tkCGSHotKeyDecreaseDisplayBrightness = 53,\n\tkCGSHotKeyIncreaseDisplayBrightness = 54,\n} CGSSymbolicHotKey;\n\n/// The possible operating modes of a hot key.\ntypedef enum {\n\t/// All hot keys are enabled app-wide.\n\tkCGSGlobalHotKeyEnable\t\t\t\t\t\t\t= 0,\n\t/// All hot keys are disabled app-wide.\n\tkCGSGlobalHotKeyDisable\t\t\t\t\t\t\t= 1,\n\t/// Hot keys are disabled app-wide, but exceptions are made for Accessibility.\n\tkCGSGlobalHotKeyDisableAllButUniversalAccess\t= 2,\n} CGSGlobalHotKeyOperatingMode;\n\n/// Options representing device-independent bits found in event modifier flags:\ntypedef enum : unsigned int {\n\t/// Set if Caps Lock key is pressed.\n\tkCGSAlphaShiftKeyMask = 1 << 16,\n\t/// Set if Shift key is pressed.\n\tkCGSShiftKeyMask      = 1 << 17,\n\t/// Set if Control key is pressed.\n\tkCGSControlKeyMask    = 1 << 18,\n\t/// Set if Option or Alternate key is pressed.\n\tkCGSAlternateKeyMask  = 1 << 19,\n\t/// Set if Command key is pressed.\n\tkCGSCommandKeyMask    = 1 << 20,\n\t/// Set if any key in the numeric keypad is pressed.\n\tkCGSNumericPadKeyMask = 1 << 21,\n\t/// Set if the Help key is pressed.\n\tkCGSHelpKeyMask       = 1 << 22,\n\t/// Set if any function key is pressed.\n\tkCGSFunctionKeyMask   = 1 << 23,\n\t/// Used to retrieve only the device-independent modifier flags, allowing applications to mask\n\t/// off the device-dependent modifier flags, including event coalescing information.\n\tkCGSDeviceIndependentModifierFlagsMask = 0xffff0000U\n} CGSModifierFlags;\n\n\n#pragma mark - Symbolic Hot Keys\n\n\n/// Gets the current global hot key operating mode for the application.\nCG_EXTERN CGError CGSGetGlobalHotKeyOperatingMode(CGSConnectionID cid, CGSGlobalHotKeyOperatingMode *outMode);\n\n/// Sets the current operating mode for the application.\n///\n/// This function can be used to enable and disable all hot key events on the given connection.\nCG_EXTERN CGError CGSSetGlobalHotKeyOperatingMode(CGSConnectionID cid, CGSGlobalHotKeyOperatingMode mode);\n\n\n#pragma mark - Symbol Hot Key Properties\n\n\n/// Returns whether the symbolic hot key represented by the given UID is enabled.\nCG_EXTERN bool CGSIsSymbolicHotKeyEnabled(CGSSymbolicHotKey hotKey);\n\n/// Sets whether the symbolic hot key represented by the given UID is enabled.\nCG_EXTERN CGError CGSSetSymbolicHotKeyEnabled(CGSSymbolicHotKey hotKey, bool isEnabled);\n\n/// Returns the values the symbolic hot key represented by the given UID is configured with.\nCG_EXTERN CGError CGSGetSymbolicHotKeyValue(CGSSymbolicHotKey hotKey, unichar *outKeyEquivalent, unichar *outVirtualKeyCode, CGSModifierFlags *outModifiers);\n\n\n#pragma mark - Custom Hot Keys\n\n\n/// Sets the value of the configuration options for the hot key represented by the given UID,\n/// creating a hot key if needed.\n///\n/// If the given UID is unique and not in use, a hot key will be instantiated for you under it.\nCG_EXTERN void CGSSetHotKey(CGSConnectionID cid, int uid, unichar options, unichar key, CGSModifierFlags modifierFlags);\n\n/// Functions like `CGSSetHotKey` but with an exclusion value.\n///\n/// The exact function of the exclusion value is unknown.  Working theory: It is supposed to be\n/// passed the UID of another existing hot key that it supresses.  Why can only one can be passed, tho?\nCG_EXTERN void CGSSetHotKeyWithExclusion(CGSConnectionID cid, int uid, unichar options, unichar key, CGSModifierFlags modifierFlags, int exclusion);\n\n/// Returns the value of the configured options for the hot key represented by the given UID.\nCG_EXTERN bool CGSGetHotKey(CGSConnectionID cid, int uid, unichar *options, unichar *key, CGSModifierFlags *modifierFlags);\n\n/// Removes a previously created hot key.\nCG_EXTERN void CGSRemoveHotKey(CGSConnectionID cid, int uid);\n\n\n#pragma mark - Custom Hot Key Properties\n\n\n/// Returns whether the hot key represented by the given UID is enabled.\nCG_EXTERN BOOL CGSIsHotKeyEnabled(CGSConnectionID cid, int uid);\n\n/// Sets whether the hot key represented by the given UID is enabled.\nCG_EXTERN void CGSSetHotKeyEnabled(CGSConnectionID cid, int uid, bool enabled);\n\n#endif /* CGS_HOTKEYS_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSInternal.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_INTERNAL_API_H\n#define CGS_INTERNAL_API_H\n\n#include <Carbon/Carbon.h>\n#include <ApplicationServices/ApplicationServices.h>\n\n// WARNING: CGSInternal contains PRIVATE FUNCTIONS and should NOT BE USED in shipping applications!\n\n#include \"CGSAccessibility.h\"\n#include \"CGSCIFilter.h\"\n#include \"CGSConnection.h\"\n#include \"CGSCursor.h\"\n#include \"CGSDebug.h\"\n#include \"CGSDevice.h\"\n#include \"CGSDisplays.h\"\n#include \"CGSEvent.h\"\n#include \"CGSHotKeys.h\"\n#include \"CGSMisc.h\"\n#include \"CGSRegion.h\"\n#include \"CGSSession.h\"\n#include \"CGSSpace.h\"\n#include \"CGSSurface.h\"\n#include \"CGSTile.h\"\n#include \"CGSTransitions.h\"\n#include \"CGSWindow.h\"\n#include \"CGSWorkspace.h\"\n\n#endif /* CGS_INTERNAL_API_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSMisc.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_MISC_INTERNAL_H\n#define CGS_MISC_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\n/// Is someone watching this screen? Applies to Apple's remote desktop only?\nCG_EXTERN bool CGSIsScreenWatcherPresent(void);\n\n#pragma mark - Error Logging\n\n/// Logs an error and returns `err`.\nCG_EXTERN CGError CGSGlobalError(CGError err, const char *msg);\n\n/// Logs an error and returns `err`.\nCG_EXTERN CGError CGSGlobalErrorv(CGError err, const char *msg, ...);\n\n/// Gets the error message for an error code.\nCG_EXTERN char *CGSErrorString(CGError error);\n\n#endif /* CGS_MISC_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSRegion.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_REGION_INTERNAL_H\n#define CGS_REGION_INTERNAL_H\n\ntypedef CFTypeRef CGSRegionRef;\ntypedef CFTypeRef CGSRegionEnumeratorRef;\n\n\n#pragma mark - Region Lifecycle\n\n\n/// Creates a region from a `CGRect`.\nCG_EXTERN CGError CGSNewRegionWithRect(const CGRect *rect, CGSRegionRef *outRegion);\n\n/// Creates a region from a list of `CGRect`s.\nCG_EXTERN CGError CGSNewRegionWithRectList(const CGRect *rects, int rectCount, CGSRegionRef *outRegion);\n\n/// Creates a new region from a QuickDraw region.\nCG_EXTERN CGError CGSNewRegionWithQDRgn(RgnHandle region, CGSRegionRef *outRegion);\n\n/// Creates an empty region.\nCG_EXTERN CGError CGSNewEmptyRegion(CGSRegionRef *outRegion);\n\n/// Releases a region.\nCG_EXTERN CGError CGSReleaseRegion(CGSRegionRef region);\n\n\n#pragma mark - Creating Complex Regions\n\n\n/// Created a new region by changing the origin an existing one.\nCG_EXTERN CGError CGSOffsetRegion(CGSRegionRef region, CGFloat offsetLeft, CGFloat offsetTop, CGSRegionRef *outRegion);\n\n/// Creates a new region by copying an existing one.\nCG_EXTERN CGError CGSCopyRegion(CGSRegionRef region, CGSRegionRef *outRegion);\n\n/// Creates a new region by combining two regions together.\nCG_EXTERN CGError CGSUnionRegion(CGSRegionRef region1, CGSRegionRef region2, CGSRegionRef *outRegion);\n\n/// Creates a new region by combining a region and a rect.\nCG_EXTERN CGError CGSUnionRegionWithRect(CGSRegionRef region, CGRect *rect, CGSRegionRef *outRegion);\n\n/// Creates a region by XORing two regions together.\nCG_EXTERN CGError CGSXorRegion(CGSRegionRef region1, CGSRegionRef region2, CGSRegionRef *outRegion);\n\n/// Creates a `CGRect` from a region.\nCG_EXTERN CGError CGSGetRegionBounds(CGSRegionRef region, CGRect *outRect);\n\n/// Creates a rect from the difference of two regions.\nCG_EXTERN CGError CGSDiffRegion(CGSRegionRef region1, CGSRegionRef region2, CGSRegionRef *outRegion);\n\n\n#pragma mark - Comparing Regions\n\n\n/// Determines if two regions are equal.\nCG_EXTERN bool CGSRegionsEqual(CGSRegionRef region1, CGSRegionRef region2);\n\n/// Determines if a region is inside of a region.\nCG_EXTERN bool CGSRegionInRegion(CGSRegionRef region1, CGSRegionRef region2);\n\n/// Determines if a region intersects a region.\nCG_EXTERN bool CGSRegionIntersectsRegion(CGSRegionRef region1, CGSRegionRef region2);\n\n/// Determines if a rect intersects a region.\nCG_EXTERN bool CGSRegionIntersectsRect(CGSRegionRef obj, const CGRect *rect);\n\n\n#pragma mark - Checking for Membership\n\n\n/// Determines if a point in a region.\nCG_EXTERN bool CGSPointInRegion(CGSRegionRef region, const CGPoint *point);\n\n/// Determines if a rect is in a region.\nCG_EXTERN bool CGSRectInRegion(CGSRegionRef region, const CGRect *rect);\n\n\n#pragma mark - Checking Region Characteristics\n\n\n/// Determines if the region is empty.\nCG_EXTERN bool CGSRegionIsEmpty(CGSRegionRef region);\n\n/// Determines if the region is rectangular.\nCG_EXTERN bool CGSRegionIsRectangular(CGSRegionRef region);\n\n\n#pragma mark - Region Enumerators\n\n\n/// Gets the enumerator for a region.\nCG_EXTERN CGSRegionEnumeratorRef CGSRegionEnumerator(CGSRegionRef region);\n\n/// Releases a region enumerator.\nCG_EXTERN void CGSReleaseRegionEnumerator(CGSRegionEnumeratorRef enumerator);\n\n/// Gets the next rect of a region.\nCG_EXTERN CGRect *CGSNextRect(CGSRegionEnumeratorRef enumerator);\n\n\n/// DOCUMENTATION PENDING */\nCG_EXTERN CGError CGSFetchDirtyScreenRegion(CGSConnectionID cid, CGSRegionRef *outDirtyRegion);\n\n#endif /* CGS_REGION_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSSession.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_SESSION_INTERNAL_H\n#define CGS_SESSION_INTERNAL_H\n\n#include \"CGSInternal.h\"\n\ntypedef int CGSSessionID;\n\n/// Creates a new \"blank\" login session.\n///\n/// Switches to the LoginWindow. This does NOT check to see if fast user switching is enabled!\nCG_EXTERN CGError CGSCreateLoginSession(CGSSessionID *outSession);\n\n/// Releases a session.\nCG_EXTERN CGError CGSReleaseSession(CGSSessionID session);\n\n/// Gets information about the current login session.\n///\n/// As of OS X 10.6, the following keys appear in this dictionary:\n///\n///     kCGSSessionGroupIDKey\t\t: CFNumberRef\n///     kCGSSessionOnConsoleKey\t\t: CFBooleanRef\n///     kCGSSessionIDKey\t\t\t: CFNumberRef\n///     kCGSSessionUserNameKey\t\t: CFStringRef\n///     kCGSessionLongUserNameKey\t: CFStringRef\n///     kCGSessionLoginDoneKey\t\t: CFBooleanRef\n///     kCGSSessionUserIDKey\t\t: CFNumberRef\n///     kCGSSessionSecureInputPID\t: CFNumberRef\nCG_EXTERN CFDictionaryRef CGSCopyCurrentSessionDictionary(void);\n\n/// Gets a list of session dictionaries.\n///\n/// Each session dictionary is in the format returned by `CGSCopyCurrentSessionDictionary`.\nCG_EXTERN CFArrayRef CGSCopySessionList(void);\n\n#endif /* CGS_SESSION_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSSpace.h",
    "content": "//\n//  CGSSpace.h\n//  CGSInternal\n//\n//  Created by Robert Widmann on 9/14/13.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_SPACE_INTERNAL_H\n#define CGS_SPACE_INTERNAL_H\n\n#include \"CGSConnection.h\"\n#include \"CGSRegion.h\"\n\ntypedef size_t CGSSpaceID;\n\n/// Representations of the possible types of spaces the system can create.\ntypedef enum {\n\t/// User-created desktop spaces.\n\tCGSSpaceTypeUser\t\t= 0,\n\t/// Fullscreen spaces.\n\tCGSSpaceTypeFullscreen\t= 1,\n\t/// System spaces e.g. Dashboard.\n\tCGSSpaceTypeSystem\t\t= 2,\n} CGSSpaceType;\n\n/// Flags that can be applied to queries for spaces.\ntypedef enum {\n\tCGSSpaceIncludesCurrent = 1 << 0,\n\tCGSSpaceIncludesOthers\t= 1 << 1,\n\tCGSSpaceIncludesUser\t= 1 << 2,\n\n\tCGSSpaceVisible\t\t\t= 1 << 16,\n\n\tkCGSCurrentSpaceMask = CGSSpaceIncludesUser | CGSSpaceIncludesCurrent,\n\tkCGSOtherSpacesMask = CGSSpaceIncludesOthers | CGSSpaceIncludesCurrent,\n\tkCGSAllSpacesMask = CGSSpaceIncludesUser | CGSSpaceIncludesOthers | CGSSpaceIncludesCurrent,\n\tKCGSAllVisibleSpacesMask = CGSSpaceVisible | kCGSAllSpacesMask,\n} CGSSpaceMask;\n\ntypedef enum {\n\t/// Each display manages a single contiguous space.\n\tkCGSPackagesSpaceManagementModeNone = 0,\n\t/// Each display manages a separate stack of spaces.\n\tkCGSPackagesSpaceManagementModePerDesktop = 1,\n} CGSSpaceManagementMode;\n\n#pragma mark - Space Lifecycle\n\n\n/// Creates a new space with the given options dictionary.\n///\n/// Valid keys are:\n///\n///     \"type\": CFNumberRef\n///     \"uuid\": CFStringRef\nCG_EXTERN CGSSpaceID CGSSpaceCreate(CGSConnectionID cid, void *null, CFDictionaryRef options);\n\n/// Removes and destroys the space corresponding to the given space ID.\nCG_EXTERN void CGSSpaceDestroy(CGSConnectionID cid, CGSSpaceID sid);\n\n\n#pragma mark - Configuring Spaces\n\n\n/// Get and set the human-readable name of a space.\nCG_EXTERN CFStringRef CGSSpaceCopyName(CGSConnectionID cid, CGSSpaceID sid);\nCG_EXTERN CGError CGSSpaceSetName(CGSConnectionID cid, CGSSpaceID sid, CFStringRef name);\n\n/// Get and set the affine transform of a space.\nCG_EXTERN CGAffineTransform CGSSpaceGetTransform(CGSConnectionID cid, CGSSpaceID space);\nCG_EXTERN void CGSSpaceSetTransform(CGSConnectionID cid, CGSSpaceID space, CGAffineTransform transform);\n\n/// Gets and sets the region the space occupies.  You are responsible for releasing the region object.\nCG_EXTERN void CGSSpaceSetShape(CGSConnectionID cid, CGSSpaceID space, CGSRegionRef shape);\nCG_EXTERN CGSRegionRef CGSSpaceCopyShape(CGSConnectionID cid, CGSSpaceID space);\n\n\n\n#pragma mark - Space Properties\n\n\n/// Copies and returns a region the space occupies.  You are responsible for releasing the region object.\nCG_EXTERN CGSRegionRef CGSSpaceCopyManagedShape(CGSConnectionID cid, CGSSpaceID sid);\n\n/// Gets the type of a space.\nCG_EXTERN CGSSpaceType CGSSpaceGetType(CGSConnectionID cid, CGSSpaceID sid);\n\n/// Gets the current space management mode.\n///\n/// This method reflects whether the “Displays have separate Spaces” option is \n/// enabled in Mission Control system preference. You might use the return value\n/// to determine how to present your app when in fullscreen mode.\nCG_EXTERN CGSSpaceManagementMode CGSGetSpaceManagementMode(CGSConnectionID cid) AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER;\n\n/// Sets the current space management mode.\nCG_EXTERN CGError CGSSetSpaceManagementMode(CGSConnectionID cid, CGSSpaceManagementMode mode) AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER;\n\n#pragma mark - Global Space Properties\n\n\n/// Gets the ID of the space currently visible to the user.\nCG_EXTERN CGSSpaceID CGSGetActiveSpace(CGSConnectionID cid);\n\n/// Returns an array of PIDs of applications that have ownership of a given space.\nCG_EXTERN CFArrayRef CGSSpaceCopyOwners(CGSConnectionID cid, CGSSpaceID sid);\n\n/// Returns an array of all space IDs.\nCG_EXTERN CFArrayRef CGSCopySpaces(CGSConnectionID cid, CGSSpaceMask mask);\n\n/// Given an array of window numbers, returns the IDs of the spaces those windows lie on.\nCG_EXTERN CFArrayRef CGSCopySpacesForWindows(CGSConnectionID cid, CGSSpaceMask mask, CFArrayRef windowIDs);\n\n\n#pragma mark - Space-Local State\n\n\n/// Connection-local data in a given space.\nCG_EXTERN CFDictionaryRef CGSSpaceCopyValues(CGSConnectionID cid, CGSSpaceID space);\nCG_EXTERN CGError CGSSpaceSetValues(CGSConnectionID cid, CGSSpaceID sid, CFDictionaryRef values);\nCG_EXTERN CGError CGSSpaceRemoveValuesForKeys(CGSConnectionID cid, CGSSpaceID sid, CFArrayRef values);\n\n\n#pragma mark - Displaying Spaces\n\n\n/// Given an array of space IDs, each space is shown to the user.\nCG_EXTERN void CGSShowSpaces(CGSConnectionID cid, CFArrayRef spaces);\n\n/// Given an array of space IDs, each space is hidden from the user.\nCG_EXTERN void CGSHideSpaces(CGSConnectionID cid, CFArrayRef spaces);\n\n/// Given an array of window numbers and an array of space IDs, adds each window to each space.\nCG_EXTERN void CGSAddWindowsToSpaces(CGSConnectionID cid, CFArrayRef windows, CFArrayRef spaces);\n\n/// Given an array of window numbers and an array of space IDs, removes each window from each space.\nCG_EXTERN void CGSRemoveWindowsFromSpaces(CGSConnectionID cid, CFArrayRef windows, CFArrayRef spaces);\n\nCG_EXTERN CFStringRef kCGSPackagesMainDisplayIdentifier;\n\n/// Changes the active space for a given display.\nCG_EXTERN void CGSManagedDisplaySetCurrentSpace(CGSConnectionID cid, CFStringRef display, CGSSpaceID space);\n\n#endif /// CGS_SPACE_INTERNAL_H */\n\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSSurface.h",
    "content": "//\n//  CGSSurface.h\n//\tCGSInternal\n//\n//  Created by Robert Widmann on 9/14/13.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_SURFACE_INTERNAL_H\n#define CGS_SURFACE_INTERNAL_H\n\n#include \"CGSWindow.h\"\n\ntypedef int CGSSurfaceID;\n\n\n#pragma mark - Surface Lifecycle\n\n\n/// Adds a drawable surface to a window.\nCG_EXTERN CGError CGSAddSurface(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID *outSID);\n\n/// Removes a drawable surface from a window.\nCG_EXTERN CGError CGSRemoveSurface(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid);\n\n/// Binds a CAContext to a surface.\n///\n/// Pass ctx the result of invoking -[CAContext contextId].\nCG_EXTERN CGError CGSBindSurface(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid, int x, int y, unsigned int ctx);\n\n#pragma mark - Surface Properties\n\n\n/// Sets the bounds of a surface.\nCG_EXTERN CGError CGSSetSurfaceBounds(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid, CGRect bounds);\n\n/// Gets the smallest rectangle a surface's frame fits in.\nCG_EXTERN CGError CGSGetSurfaceBounds(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid, CGFloat *bounds);\n\n/// Sets the opacity of the surface\nCG_EXTERN CGError CGSSetSurfaceOpacity(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid, bool isOpaque);\n\n/// Sets a surface's color space.\nCG_EXTERN CGError CGSSetSurfaceColorSpace(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID surface, CGColorSpaceRef colorSpace);\n\n/// Tunes a number of properties the Window Server uses when rendering a layer-backed surface.\nCG_EXTERN CGError CGSSetSurfaceLayerBackingOptions(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID surface, CGFloat flattenDelay, CGFloat decelerationDelay, CGFloat discardDelay);\n\n/// Sets the order of a surface relative to another surface.\nCG_EXTERN CGError CGSOrderSurface(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID surface, CGSSurfaceID otherSurface, int place);\n\n/// Currently does nothing.\nCG_EXTERN CGError CGSSetSurfaceBackgroundBlur(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid, CGFloat blur) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n/// Sets the drawing resolution of the surface.\nCG_EXTERN CGError CGSSetSurfaceResolution(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID sid, CGFloat scale) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n\n#pragma mark - Window Surface Properties\n\n\n/// Gets the count of all drawable surfaces on a window.\nCG_EXTERN CGError CGSGetSurfaceCount(CGSConnectionID cid, CGWindowID wid, int *outCount);\n\n/// Gets a list of surfaces owned by a window.\nCG_EXTERN CGError CGSGetSurfaceList(CGSConnectionID cid, CGWindowID wid, int countIds, CGSSurfaceID *ids, int *outCount);\n\n\n#pragma mark - Drawing Surfaces\n\n\n/// Flushes a surface to its window.\nCG_EXTERN CGError CGSFlushSurface(CGSConnectionID cid, CGWindowID wid, CGSSurfaceID surface, int param);\n\n#endif /* CGS_SURFACE_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSTile.h",
    "content": "//\n//  CGSTile.h\n//  NUIKit\n//\n//  Created by Robert Widmann on 10/9/15.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_TILE_INTERNAL_H\n#define CGS_TILE_INTERNAL_H\n\n#include \"CGSSurface.h\"\n\ntypedef size_t CGSTileID;\n\n\n#pragma mark - Proposed Tile Properties\n\n\n/// Returns true if the space ID and connection admit the creation of a new tile.\nCG_EXTERN bool CGSSpaceCanCreateTile(CGSConnectionID cid, CGSSpaceID sid) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n/// Returns the recommended size for a tile that could be added to the given space.\nCG_EXTERN CGError CGSSpaceGetSizeForProposedTile(CGSConnectionID cid, CGSSpaceID sid, CGSize *outSize) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n\n#pragma mark - Tile Creation\n\n\n/// Creates a new tile ID in the given space.\nCG_EXTERN CGError CGSSpaceCreateTile(CGSConnectionID cid, CGSSpaceID sid, CGSTileID *outTID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n\n#pragma mark - Tile Spaces\n\n\n/// Returns an array of CFNumberRefs of CGSSpaceIDs.\nCG_EXTERN CFArrayRef CGSSpaceCopyTileSpaces(CGSConnectionID cid, CGSSpaceID sid) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n\n#pragma mark - Tile Properties\n\n\n/// Returns the size of the inter-tile spacing between tiles in the given space ID.\nCG_EXTERN CGFloat CGSSpaceGetInterTileSpacing(CGSConnectionID cid, CGSSpaceID sid) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n/// Sets the size of the inter-tile spacing for the given space ID.\nCG_EXTERN CGError CGSSpaceSetInterTileSpacing(CGSConnectionID cid, CGSSpaceID sid, CGFloat spacing) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n/// Gets the space ID for the given tile space.\nCG_EXTERN CGSSpaceID CGSTileSpaceResizeRecordGetSpaceID(CGSSpaceID sid) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n/// Gets the space ID for the parent of the given tile space.\nCG_EXTERN CGSSpaceID CGSTileSpaceResizeRecordGetParentSpaceID(CGSSpaceID sid) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n/// Returns whether the current tile space is being resized.\nCG_EXTERN bool CGSTileSpaceResizeRecordIsLiveResizing(CGSSpaceID sid) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n///\nCG_EXTERN CGSTileID CGSTileOwnerChangeRecordGetTileID(CGSConnectionID ownerID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n///\nCG_EXTERN CGSSpaceID CGSTileOwnerChangeRecordGetManagedSpaceID(CGSConnectionID ownerID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n///\nCG_EXTERN CGSTileID CGSTileEvictionRecordGetTileID(CGSConnectionID ownerID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n///\nCG_EXTERN CGSSpaceID CGSTileEvictionRecordGetManagedSpaceID(CGSConnectionID ownerID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n///\nCG_EXTERN CGSSpaceID CGSTileOwnerChangeRecordGetNewOwner(CGSConnectionID ownerID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n///\nCG_EXTERN CGSSpaceID CGSTileOwnerChangeRecordGetOldOwner(CGSConnectionID ownerID) AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER;\n\n#endif /* CGS_TILE_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSTransitions.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_TRANSITIONS_INTERNAL_H\n#define CGS_TRANSITIONS_INTERNAL_H\n\n#include \"CGSConnection.h\"\n\ntypedef enum {\n\t/// No animation is performed during the transition.\n\tkCGSTransitionNone,\n\t/// The window's content fades as it becomes visible or hidden.\n\tkCGSTransitionFade,\n\t/// The window's content zooms in or out as it becomes visible or hidden.\n\tkCGSTransitionZoom,\n\t/// The window's content is revealed gradually in the direction specified by the transition subtype.\n\tkCGSTransitionReveal,\n\t/// The window's content slides in or out along the direction specified by the transition subtype.\n\tkCGSTransitionSlide,\n\t///\n\tkCGSTransitionWarpFade,\n\tkCGSTransitionSwap,\n\t/// The window's content is aligned to the faces of a cube and rotated in or out along the\n\t/// direction specified by the transition subtype.\n\tkCGSTransitionCube,\n\t///\n\tkCGSTransitionWarpSwitch,\n\t/// The window's content is flipped along its midpoint like a page being turned over along the\n\t/// direction specified by the transition subtype.\n\tkCGSTransitionFlip\n} CGSTransitionType;\n\ntypedef enum {\n\t/// Directions bits for the transition. Some directions don't apply to some transitions.\n\tkCGSTransitionDirectionLeft\t\t= 1 << 0,\n\tkCGSTransitionDirectionRight\t= 1 << 1,\n\tkCGSTransitionDirectionDown\t\t= 1 << 2,\n\tkCGSTransitionDirectionUp\t\t=\t1 << 3,\n\tkCGSTransitionDirectionCenter\t= 1 << 4,\n\t\n\t/// Reverses a transition. Doesn't apply for all transitions.\n\tkCGSTransitionFlagReversed\t\t= 1 << 5,\n\t\n\t/// Ignore the background color and only transition the window.\n\tkCGSTransitionFlagTransparent\t= 1 << 7,\n} CGSTransitionFlags;\n\ntypedef struct CGSTransitionSpec {\n\tint version; // always set to zero\n\tCGSTransitionType type;\n\tCGSTransitionFlags options;\n\tCGWindowID wid; /* 0 means a full screen transition. */\n\tCGFloat *backColor; /* NULL means black. */\n} *CGSTransitionSpecRef;\n\n/// Creates a new transition from a `CGSTransitionSpec`.\nCG_EXTERN CGError CGSNewTransition(CGSConnectionID cid, const CGSTransitionSpecRef spec, CGSTransitionID *outTransition);\n\n/// Invokes a transition asynchronously. Note that `duration` is in seconds.\nCG_EXTERN CGError CGSInvokeTransition(CGSConnectionID cid, CGSTransitionID transition, CGFloat duration);\n\n/// Releases a transition.\nCG_EXTERN CGError CGSReleaseTransition(CGSConnectionID cid, CGSTransitionID transition);\n\n#endif /* CGS_TRANSITIONS_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSWindow.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_WINDOW_INTERNAL_H\n#define CGS_WINDOW_INTERNAL_H\n\n#include \"CGSConnection.h\"\n#include \"CGSRegion.h\"\n\ntypedef CFTypeRef CGSAnimationRef;\ntypedef CFTypeRef CGSWindowBackdropRef;\ntypedef struct CGSWarpPoint CGSWarpPoint;\n\n#define kCGSRealMaximumTagSize (sizeof(void *) * 8)\n\ntypedef enum {\n\tkCGSSharingNone,\n\tkCGSSharingReadOnly,\n\tkCGSSharingReadWrite\n} CGSSharingState;\n\ntypedef enum {\n\tkCGSOrderBelow = -1,\n\tkCGSOrderOut, /* hides the window */\n\tkCGSOrderAbove,\n\tkCGSOrderIn /* shows the window */\n} CGSWindowOrderingMode;\n\ntypedef enum {\n\tkCGSBackingNonRetianed,\n\tkCGSBackingRetained,\n\tkCGSBackingBuffered,\n} CGSBackingType;\n\ntypedef enum {\n\tCGSWindowSaveWeightingDontReuse,\n\tCGSWindowSaveWeightingTopLeft,\n\tCGSWindowSaveWeightingTopRight,\n\tCGSWindowSaveWeightingBottomLeft,\n\tCGSWindowSaveWeightingBottomRight,\n\tCGSWindowSaveWeightingClip,\n} CGSWindowSaveWeighting;\ntypedef enum : int {\n\t// Lo bits\n\t\n\t/// The window appears in the default style of OS X windows.  \"Document\" is most likely a\n\t/// historical name.\n\tkCGSDocumentWindowTagBit\t\t\t\t\t\t= 1 << 0,\n\t/// The window appears floating over other windows.  This mask is often combined with other\n\t/// non-activating bits to enable floating panels.\n\tkCGSFloatingWindowTagBit\t\t\t\t\t\t= 1 << 1,\n\t\n\t/// Disables the window's badging when it is minimized into its Dock Tile.\n\tkCGSDoNotShowBadgeInDockTagBit\t\t\t\t\t= 1 << 2,\n\t\n\t/// The window will be displayed without a shadow, and will ignore any given shadow parameters.\n\tkCGSDisableShadowTagBit\t\t\t\t\t\t\t= 1 << 3,\n\t\n\t/// Causes the Window Server to resample the window at a higher rate.  While this may lead to an\n\t/// improvement in the look of the window, it can lead to performance issues.\n\tkCGSHighQualityResamplingTagBit\t\t\t\t\t= 1 << 4,\n\t\n\t/// The window may set the cursor when the application is not active.  Useful for windows that\n\t/// present controls like editable text fields.\n\tkCGSSetsCursorInBackgroundTagBit\t\t\t\t= 1 << 5,\n\t\n\t/// The window continues to operate while a modal run loop has been pushed.\n\tkCGSWorksWhenModalTagBit\t\t\t\t\t\t= 1 << 6,\n\t\n\t/// The window is anchored to another window.\n\tkCGSAttachedWindowTagBit\t\t\t\t\t\t= 1 << 7,\n\n\t/// When dragging, the window will ignore any alpha and appear 100% opaque.\n\tkCGSIgnoreAlphaForDraggingTagBit\t\t\t\t= 1 << 8,\n\t\n\t/// The window appears transparent to events.  Mouse events will pass through it to the next\n\t/// eligible responder.  This bit or kCGSOpaqueForEventsTagBit must be exclusively set.\n\tkCGSIgnoreForEventsTagBit\t\t\t\t\t\t= 1 << 9,\n\t/// The window appears opaque to events.  Mouse events will be intercepted by the window when\n\t/// necessary.  This bit or kCGSIgnoreForEventsTagBit must be exclusively set.\n\tkCGSOpaqueForEventsTagBit\t\t\t\t\t\t= 1 << 10,\n\t\n\t/// The window appears on all workspaces regardless of where it was created.  This bit is used\n\t/// for QuickLook panels.\n\tkCGSOnAllWorkspacesTagBit\t\t\t\t\t\t= 1 << 11,\n\n\t///\n\tkCGSPointerEventsAvoidCPSTagBit\t\t\t\t\t= 1 << 12,\n\t\n\t///\n\tkCGSKitVisibleTagBit\t\t\t\t\t\t\t= 1 << 13,\n\t\n\t/// On application deactivation the window disappears from the window list.\n\tkCGSHideOnDeactivateTagBit\t\t\t\t\t\t= 1 << 14,\n\t\n\t/// When the window appears it will not bring the application to the forefront.\n\tkCGSAvoidsActivationTagBit\t\t\t\t\t\t= 1 << 15,\n\t/// When the window is selected it will not bring the application to the forefront.\n\tkCGSPreventsActivationTagBit\t\t\t\t\t= 1 << 16,\n\t\n\t///\n\tkCGSIgnoresOptionTagBit\t\t\t\t\t\t\t= 1 << 17,\n\t\n\t/// The window ignores the window cycling mechanism.\n\tkCGSIgnoresCycleTagBit\t\t\t\t\t\t\t= 1 << 18,\n \n\t///\n\tkCGSDefersOrderingTagBit\t\t\t\t\t\t= 1 << 19,\n\t\n\t///\n\tkCGSDefersActivationTagBit\t\t\t\t\t\t= 1 << 20,\n\t\n\t/// WindowServer will ignore all requests to order this window front.\n\tkCGSIgnoreAsFrontWindowTagBit\t\t\t\t\t= 1 << 21,\n\t\n\t/// The WindowServer will control the movement of the window on the screen using its given\n\t/// dragging rects.  This enables windows to be movable even when the application stalls.\n\tkCGSEnableServerSideDragTagBit\t\t\t\t\t= 1 << 22,\n\t\n\t///\n\tkCGSMouseDownEventsGrabbedTagBit\t\t\t\t= 1 << 23,\n\t\n\t/// The window ignores all requests to hide.\n\tkCGSDontHideTagBit\t\t\t\t\t\t\t\t= 1 << 24,\n\t\n\t///\n\tkCGSDontDimWindowDisplayTagBit\t\t\t\t\t= 1 << 25,\n\t\n\t/// The window converts all pointers, no matter if they are mice or tablet pens, to its pointer\n\t/// type when they enter the window.\n\tkCGSInstantMouserWindowTagBit\t\t\t\t\t= 1 << 26,\n\t\n\t/// The window appears only on active spaces, and will follow when the user changes said active\n\t/// space.\n\tkCGSWindowOwnerFollowsForegroundTagBit\t\t\t= 1 << 27,\n\t\n\t///\n\tkCGSActivationWindowLevelTagBit\t\t\t\t\t= 1 << 28,\n\t\n\t/// The window brings its owning application to the forefront when it is selected.\n\tkCGSBringOwningApplicationForwardTagBit\t\t\t= 1 << 29,\n\t\n\t/// The window is allowed to appear when over login screen.\n\tkCGSPermittedBeforeLoginTagBit\t\t\t\t\t= 1 << 30,\n\t\n\t/// The window is modal.\n\tkCGSModalWindowTagBit\t\t\t\t\t\t\t= 1 << 31,\n\n\t// Hi bits\n\t\n\t/// The window draws itself like the dock -the \"Magic Mirror\".\n\tkCGSWindowIsMagicMirrorTagBit\t\t\t\t\t= 1 << 1,\n\t\n\t///\n\tkCGSFollowsUserTagBit\t\t\t\t\t\t\t= 1 << 2,\n\t\n\t///\n\tkCGSWindowDoesNotCastMirrorReflectionTagBit\t\t= 1 << 3,\n\t\n\t///\n\tkCGSMeshedWindowTagBit\t\t\t\t\t\t\t= 1 << 4,\n\t\n\t/// Bit is set when CoreDrag has dragged something to the window.\n\tkCGSCoreDragIsDraggingWindowTagBit\t\t\t\t= 1 << 5,\n\t\n\t///\n\tkCGSAvoidsCaptureTagBit\t\t\t\t\t\t\t= 1 << 6,\n\t\n\t/// The window is ignored for expose and does not change its appearance in any way when it is\n\t/// activated.\n\tkCGSIgnoreForExposeTagBit\t\t\t\t\t\t= 1 << 7,\n\t\n\t/// The window is hidden.\n\tkCGSHiddenTagBit\t\t\t\t\t\t\t\t= 1 << 8,\n\t\n\t/// The window is explicitly included in the window cycling mechanism.\n\tkCGSIncludeInCycleTagBit\t\t\t\t\t\t= 1 << 9,\n\t\n\t/// The window captures gesture events even when the application is not in the foreground.\n\tkCGSWantGesturesInBackgroundTagBit\t\t\t\t= 1 << 10,\n\t\n\t/// The window is fullscreen.\n\tkCGSFullScreenTagBit\t\t\t\t\t\t\t= 1 << 11,\n\t\n\t///\n\tkCGSWindowIsMagicZoomTagBit\t\t\t\t\t\t= 1 << 12,\n\t\n\t///\n\tkCGSSuperStickyTagBit\t\t\t\t\t\t\t= 1 << 13,\n\t\n\t/// The window is attached to the menu bar.  This is used for NSMenus presented by menu bar\n\t/// apps.\n\tkCGSAttachesToMenuBarTagBit\t\t\t\t\t\t= 1 << 14,\n\t\n\t/// The window appears on the menu bar.  This is used for all menu bar items.\n\tkCGSMergesWithMenuBarTagBit\t\t\t\t\t\t= 1 << 15,\n\t\n\t///\n\tkCGSNeverStickyTagBit\t\t\t\t\t\t\t= 1 << 16,\n\t\n\t/// The window appears at the level of the desktop picture.\n\tkCGSDesktopPictureTagBit\t\t\t\t\t\t= 1 << 17,\n\t\n\t/// When the window is redrawn it moves forward.  Useful for debugging, annoying in practice.\n\tkCGSOrdersForwardWhenSurfaceFlushedTagBit\t\t= 1 << 18,\n\t\n\t/// \n\tkCGSDragsMovementGroupParentTagBit\t\t\t\t= 1 << 19,\n\tkCGSNeverFlattenSurfacesDuringSwipesTagBit\t\t= 1 << 20,\n\tkCGSFullScreenCapableTagBit\t\t\t\t\t\t= 1 << 21,\n\tkCGSFullScreenTileCapableTagBit\t\t\t\t\t= 1 << 22,\n} CGSWindowTagBit;\n\nstruct CGSWarpPoint {\n\tCGPoint localPoint;\n\tCGPoint globalPoint;\n};\n\n\n#pragma mark - Creating Windows\n\n\n/// Creates a new CGSWindow.\n///\n/// The real window top/left is the sum of the region's top/left and the top/left parameters.\nCG_EXTERN CGError CGSNewWindow(CGSConnectionID cid, CGSBackingType backingType, CGFloat left, CGFloat top, CGSRegionRef region, CGWindowID *outWID);\n\n/// Creates a new CGSWindow.\n///\n/// The real window top/left is the sum of the region's top/left and the top/left parameters.\nCG_EXTERN CGError CGSNewWindowWithOpaqueShape(CGSConnectionID cid, CGSBackingType backingType, CGFloat left, CGFloat top, CGSRegionRef region, CGSRegionRef opaqueShape, int unknown, CGSWindowTagBit *tags, int tagSize, CGWindowID *outWID);\n\n/// Releases a CGSWindow.\nCG_EXTERN CGError CGSReleaseWindow(CGSConnectionID cid, CGWindowID wid);\n\n\n#pragma mark - Configuring Windows\n\n\n/// Gets the value associated with the specified window property as a CoreFoundation object.\nCG_EXTERN CGError CGSGetWindowProperty(CGSConnectionID cid, CGWindowID wid, CFStringRef key, CFTypeRef *outValue);\nCG_EXTERN CGError CGSSetWindowProperty(CGSConnectionID cid, CGWindowID wid, CFStringRef key, CFTypeRef value);\n\n/// Sets the window's title.\n///\n/// A window's title and what is displayed on its titlebar are often distinct strings.  The value\n/// passed to this method is used to identify the window in spaces.\n///\n/// Internally this calls `CGSSetWindowProperty(cid, wid, kCGSWindowTitle, title)`.\nCG_EXTERN CGError CGSSetWindowTitle(CGSConnectionID cid, CGWindowID wid, CFStringRef title);\n\n\n/// Returns the window’s alpha value.\nCG_EXTERN CGError CGSGetWindowAlpha(CGSConnectionID cid, CGWindowID wid, CGFloat *outAlpha);\n\n/// Sets the window's alpha value.\nCG_EXTERN CGError CGSSetWindowAlpha(CGSConnectionID cid, CGWindowID wid, CGFloat alpha);\n\n/// Sets the shape of the window and describes how to redraw if the bounding\n/// boxes don't match.\nCG_EXTERN CGError CGSSetWindowShapeWithWeighting(CGSConnectionID cid, CGWindowID wid, CGFloat offsetX, CGFloat offsetY, CGSRegionRef shape, CGSWindowSaveWeighting weight);\n\n/// Sets the shape of the window.\nCG_EXTERN CGError CGSSetWindowShape(CGSConnectionID cid, CGWindowID wid, CGFloat offsetX, CGFloat offsetY, CGSRegionRef shape);\n\n/// Gets and sets a Boolean value indicating whether the window is opaque.\nCG_EXTERN CGError CGSGetWindowOpacity(CGSConnectionID cid, CGWindowID wid, bool *outIsOpaque);\nCG_EXTERN CGError CGSSetWindowOpacity(CGSConnectionID cid, CGWindowID wid, bool isOpaque);\n\n/// Gets and sets the window's color space.\nCG_EXTERN CGError CGSCopyWindowColorSpace(CGSConnectionID cid, CGWindowID wid, CGColorSpaceRef *outColorSpace);\nCG_EXTERN CGError CGSSetWindowColorSpace(CGSConnectionID cid, CGWindowID wid, CGColorSpaceRef colorSpace);\n\n/// Gets and sets the window's clip shape.\nCG_EXTERN CGError CGSCopyWindowClipShape(CGSConnectionID cid, CGWindowID wid, CGSRegionRef *outRegion);\nCG_EXTERN CGError CGSSetWindowClipShape(CGWindowID wid, CGSRegionRef shape);\n\n/// Gets and sets the window's transform. \n///\n///\tSevere restrictions are placed on transformation:\n/// - Transformation Matrices may only include a singular transform.\n/// - Transformations involving scale may not scale upwards past the window's frame.\n/// - Transformations involving rotation must be followed by translation or the window will fall offscreen.\nCG_EXTERN CGError CGSGetWindowTransform(CGSConnectionID cid, CGWindowID wid, const CGAffineTransform *outTransform);\nCG_EXTERN CGError CGSSetWindowTransform(CGSConnectionID cid, CGWindowID wid, CGAffineTransform transform);\n\n/// Gets and sets the window's transform in place. \n///\n///\tSevere restrictions are placed on transformation:\n/// - Transformation Matrices may only include a singular transform.\n/// - Transformations involving scale may not scale upwards past the window's frame.\n/// - Transformations involving rotation must be followed by translation or the window will fall offscreen.\nCG_EXTERN CGError CGSGetWindowTransformAtPlacement(CGSConnectionID cid, CGWindowID wid, const CGAffineTransform *outTransform);\nCG_EXTERN CGError CGSSetWindowTransformAtPlacement(CGSConnectionID cid, CGWindowID wid, CGAffineTransform transform);\n\n/// Gets and sets the `CGConnectionID` that owns this window. Only the owner can change most properties of the window.\nCG_EXTERN CGError CGSGetWindowOwner(CGSConnectionID cid, CGWindowID wid, CGSConnectionID *outOwner);\nCG_EXTERN CGError CGSSetWindowOwner(CGSConnectionID cid, CGWindowID wid, CGSConnectionID owner);\n\n/// Sets the background color of the window.\nCG_EXTERN CGError CGSSetWindowAutofillColor(CGSConnectionID cid, CGWindowID wid, CGFloat red, CGFloat green, CGFloat blue);\n\n/// Sets the warp for the window. The mesh maps a local (window) point to a point on screen.\nCG_EXTERN CGError CGSSetWindowWarp(CGSConnectionID cid, CGWindowID wid, int warpWidth, int warpHeight, const CGSWarpPoint *warp);\n\n/// Gets or sets whether the Window Server should auto-fill the window's background.\nCG_EXTERN CGError CGSGetWindowAutofill(CGSConnectionID cid, CGWindowID wid, bool *outShouldAutoFill);\nCG_EXTERN CGError CGSSetWindowAutofill(CGSConnectionID cid, CGWindowID wid, bool shouldAutoFill);\n\n/// Gets and sets the window level for a window.\nCG_EXTERN CGError CGSGetWindowLevel(CGSConnectionID cid, CGWindowID wid, CGWindowLevel *outLevel);\nCG_EXTERN CGError CGSSetWindowLevel(CGSConnectionID cid, CGWindowID wid, CGWindowLevel level);\n\n/// Gets and sets the sharing state. This determines the level of access other applications have over this window.\nCG_EXTERN CGError CGSGetWindowSharingState(CGSConnectionID cid, CGWindowID wid, CGSSharingState *outState);\nCG_EXTERN CGError CGSSetWindowSharingState(CGSConnectionID cid, CGWindowID wid, CGSSharingState state);\n\n/// Sets whether this window is ignored in the global window cycle (Control-F4 by default). There is no Get version? */\nCG_EXTERN CGError CGSSetIgnoresCycle(CGSConnectionID cid, CGWindowID wid, bool ignoresCycle);\n\n\n#pragma mark - Managing Window Key State\n\n\n/// Forces a window to acquire key window status.\nCG_EXTERN CGError CGSSetMouseFocusWindow(CGSConnectionID cid, CGWindowID wid);\n\n/// Forces a window to draw with its key appearance.\nCG_EXTERN CGError CGSSetWindowHasKeyAppearance(CGSConnectionID cid, CGWindowID wid, bool hasKeyAppearance);\n\n/// Forces a window to be active.\nCG_EXTERN CGError CGSSetWindowActive(CGSConnectionID cid, CGWindowID wid, bool isActive);\n\n\n#pragma mark - Handling Events\n\n/// DEPRECATED: Sets the shape over which the window can capture events in its frame rectangle.\nCG_EXTERN CGError CGSSetWindowEventShape(CGSConnectionID cid, CGSBackingType backingType, CGSRegionRef *shape);\n\n/// Gets and sets the window's event mask.\nCG_EXTERN CGError CGSGetWindowEventMask(CGSConnectionID cid, CGWindowID wid, CGEventMask *mask);\nCG_EXTERN CGError CGSSetWindowEventMask(CGSConnectionID cid, CGWindowID wid, CGEventMask mask);\n\n/// Sets whether a window can recieve mouse events.  If no, events will pass to the next window that can receive the event.\nCG_EXTERN CGError CGSSetMouseEventEnableFlags(CGSConnectionID cid, CGWindowID wid, bool shouldEnable);\n\n\n\n/// Gets the screen rect for a window.\nCG_EXTERN CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGWindowID wid, CGRect *outRect);\n\n\n#pragma mark - Drawing Windows\n\n/// Creates a graphics context for the window. \n///\n/// Acceptable keys options:\n///\n/// - CGWindowContextShouldUseCA : CFBooleanRef\nCG_EXTERN CGContextRef CGWindowContextCreate(CGSConnectionID cid, CGWindowID wid, CFDictionaryRef options);\n\n/// Flushes a window's buffer to the screen.\nCG_EXTERN CGError CGSFlushWindow(CGSConnectionID cid, CGWindowID wid, CGSRegionRef flushRegion);\n\n\n#pragma mark - Window Order\n\n\n/// Sets the order of a window.\nCG_EXTERN CGError CGSOrderWindow(CGSConnectionID cid, CGWindowID wid, CGSWindowOrderingMode mode, CGWindowID relativeToWID);\n\nCG_EXTERN CGError CGSOrderFrontConditionally(CGSConnectionID cid, CGWindowID wid, bool force);\n\n\n#pragma mark - Sizing Windows\n\n\n/// Sets the origin (top-left) of a window.\nCG_EXTERN CGError CGSMoveWindow(CGSConnectionID cid, CGWindowID wid, const CGPoint *origin);\n\n/// Sets the origin (top-left) of a window relative to another window's origin.\nCG_EXTERN CGError CGSSetWindowOriginRelativeToWindow(CGSConnectionID cid, CGWindowID wid, CGWindowID relativeToWID, CGFloat offsetX, CGFloat offsetY);\n\n/// Sets the frame and position of a window.  Updates are grouped for the sake of animation.\nCG_EXTERN CGError CGSMoveWindowWithGroup(CGSConnectionID cid, CGWindowID wid, CGRect *newFrame);\n\n/// Gets the mouse's current location inside the bounds rectangle of the window.\nCG_EXTERN CGError CGSGetWindowMouseLocation(CGSConnectionID cid, CGWindowID wid, CGPoint *outPos);\n\n\n#pragma mark - Window Shadows\n\n\n/// Sets the shadow information for a window.\n///\n/// Calls through to `CGSSetWindowShadowAndRimParameters` passing 1 for `flags`.\nCG_EXTERN CGError CGSSetWindowShadowParameters(CGSConnectionID cid, CGWindowID wid, CGFloat standardDeviation, CGFloat density, int offsetX, int offsetY);\n\n/// Gets and sets the shadow information for a window.\n///\n/// Values for `flags` are unknown.  Calls `CGSSetWindowShadowAndRimParametersWithStretch`.\nCG_EXTERN CGError CGSSetWindowShadowAndRimParameters(CGSConnectionID cid, CGWindowID wid, CGFloat standardDeviation, CGFloat density, int offsetX, int offsetY, int flags);\nCG_EXTERN CGError CGSGetWindowShadowAndRimParameters(CGSConnectionID cid, CGWindowID wid, CGFloat *outStandardDeviation, CGFloat *outDensity, int *outOffsetX, int *outOffsetY, int *outFlags);\n\n/// Sets the shadow information for a window.\nCG_EXTERN CGError CGSSetWindowShadowAndRimParametersWithStretch(CGSConnectionID cid, CGWindowID wid, CGFloat standardDeviation, CGFloat density, int offsetX, int offsetY, int stretch_x, int stretch_y, unsigned int flags);\n\n/// Invalidates a window's shadow.\nCG_EXTERN CGError CGSInvalidateWindowShadow(CGSConnectionID cid, CGWindowID wid);\n\n/// Sets a window's shadow properties.\n///\n/// Acceptable keys:\n///\n/// - com.apple.WindowShadowDensity\t\t\t- (0.0 - 1.0) Opacity of the window's shadow.\n/// - com.apple.WindowShadowRadius\t\t\t- The radius of the shadow around the window's corners.\n/// - com.apple.WindowShadowVerticalOffset\t- Vertical offset of the shadow.\n/// - com.apple.WindowShadowRimDensity\t\t- (0.0 - 1.0) Opacity of the black rim around the window.\n/// - com.apple.WindowShadowRimStyleHard\t- Sets a hard black rim around the window.\nCG_EXTERN CGError CGSWindowSetShadowProperties(CGWindowID wid, CFDictionaryRef properties);\n\n\n#pragma mark - Window Lists\n\n\n/// Gets the number of windows the `targetCID` owns.\nCG_EXTERN CGError CGSGetWindowCount(CGSConnectionID cid, CGSConnectionID targetCID, int *outCount);\n\n/// Gets a list of windows owned by `targetCID`.\nCG_EXTERN CGError CGSGetWindowList(CGSConnectionID cid, CGSConnectionID targetCID, int count, CGWindowID *list, int *outCount);\n\n/// Gets the number of windows owned by `targetCID` that are on screen.\nCG_EXTERN CGError CGSGetOnScreenWindowCount(CGSConnectionID cid, CGSConnectionID targetCID, int *outCount);\n\n/// Gets a list of windows oned by `targetCID` that are on screen.\nCG_EXTERN CGError CGSGetOnScreenWindowList(CGSConnectionID cid, CGSConnectionID targetCID, int count, CGWindowID *list, int *outCount);\n\n/// Sets the alpha of a group of windows over a period of time. Note that `duration` is in seconds.\nCG_EXTERN CGError CGSSetWindowListAlpha(CGSConnectionID cid, const CGWindowID *widList, int widCount, CGFloat alpha, CGFloat duration);\n\n\n#pragma mark - Window Activation Regions\n\n\n/// Sets the shape over which the window can capture events in its frame rectangle.\nCG_EXTERN CGError CGSAddActivationRegion(CGSConnectionID cid, CGWindowID wid, CGSRegionRef region);\n\n/// Sets the shape over which the window can recieve mouse drag events.\nCG_EXTERN CGError CGSAddDragRegion(CGSConnectionID cid, CGWindowID wid, CGSRegionRef region);\n\n/// Removes any shapes over which the window can be dragged.\nCG_EXTERN CGError CGSClearDragRegion(CGSConnectionID cid, CGWindowID wid);\n\nCG_EXTERN CGError CGSDragWindowRelativeToMouse(CGSConnectionID cid, CGWindowID wid, CGPoint point);\n\n\n#pragma mark - Window Animations\n\n\n/// Creates a Dock-style genie animation that goes from `wid` to `destinationWID`.\nCG_EXTERN CGError CGSCreateGenieWindowAnimation(CGSConnectionID cid, CGWindowID wid, CGWindowID destinationWID, CGSAnimationRef *outAnimation);\n\n/// Creates a sheet animation that's used when the parent window is brushed metal. Oddly enough, seems to be the only one used, even if the parent window isn't metal.\nCG_EXTERN CGError CGSCreateMetalSheetWindowAnimationWithParent(CGSConnectionID cid, CGWindowID wid, CGWindowID parentWID, CGSAnimationRef *outAnimation);\n\n/// Sets the progress of an animation.\nCG_EXTERN CGError CGSSetWindowAnimationProgress(CGSAnimationRef animation, CGFloat progress);\n\n/// DOCUMENTATION PENDING */\nCG_EXTERN CGError CGSWindowAnimationChangeLevel(CGSAnimationRef animation, CGWindowLevel level);\n\n/// DOCUMENTATION PENDING */\nCG_EXTERN CGError CGSWindowAnimationSetParent(CGSAnimationRef animation, CGWindowID parent) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;\n\n/// Releases a window animation.\nCG_EXTERN CGError CGSReleaseWindowAnimation(CGSAnimationRef animation);\n\n\n#pragma mark - Window Accelleration\n\n\n/// Gets the state of accelleration for the window.\nCG_EXTERN CGError CGSWindowIsAccelerated(CGSConnectionID cid, CGWindowID wid, bool *outIsAccelerated);\n\n/// Gets and sets if this window can be accellerated. I don't know if playing with this is safe.\nCG_EXTERN CGError CGSWindowCanAccelerate(CGSConnectionID cid, CGWindowID wid, bool *outCanAccelerate);\nCG_EXTERN CGError CGSWindowSetCanAccelerate(CGSConnectionID cid, CGWindowID wid, bool canAccelerate);\n\n\n#pragma mark - Status Bar Windows\n\n\n/// Registers or unregisters a window as a global status item (see `NSStatusItem`, `NSMenuExtra`).\n/// Once a window is registered, the Window Server takes care of placing it in the apropriate location.\nCG_EXTERN CGError CGSSystemStatusBarRegisterWindow(CGSConnectionID cid, CGWindowID wid, int priority);\nCG_EXTERN CGError CGSUnregisterWindowWithSystemStatusBar(CGSConnectionID cid, CGWindowID wid);\n\n/// Rearranges items in the system status bar. You should call this after registering or unregistering a status item or changing the window's width.\nCG_EXTERN CGError CGSAdjustSystemStatusBarWindows(CGSConnectionID cid);\n\n\n#pragma mark - Window Tags\n\n\n/// Get the given tags for a window.  Pass kCGSRealMaximumTagSize to maxTagSize.\n///\n/// Tags are represented server-side as 64-bit integers, but CoreGraphics maintains compatibility\n/// with 32-bit clients by requiring 2 32-bit options tags to be specified.  The first entry in the\n/// options array populates the lower 32 bits, the last populates the upper 32 bits.\nCG_EXTERN CGError CGSGetWindowTags(CGSConnectionID cid, CGWindowID wid, const CGSWindowTagBit tags[2], size_t maxTagSize);\n\n/// Set the given tags for a window.  Pass kCGSRealMaximumTagSize to maxTagSize.\n///\n/// Tags are represented server-side as 64-bit integers, but CoreGraphics maintains compatibility\n/// with 32-bit clients by requiring 2 32-bit options tags to be specified.  The first entry in the\n/// options array populates the lower 32 bits, the last populates the upper 32 bits.\nCG_EXTERN CGError CGSSetWindowTags(CGSConnectionID cid, CGWindowID wid, const CGSWindowTagBit tags[2], size_t maxTagSize);\n\n/// Clear the given tags for a window.  Pass kCGSRealMaximumTagSize to maxTagSize. \n///\n/// Tags are represented server-side as 64-bit integers, but CoreGraphics maintains compatibility\n/// with 32-bit clients by requiring 2 32-bit options tags to be specified.  The first entry in the\n/// options array populates the lower 32 bits, the last populates the upper 32 bits.\nCG_EXTERN CGError CGSClearWindowTags(CGSConnectionID cid, CGWindowID wid, const CGSWindowTagBit tags[2], size_t maxTagSize);\n\n\n#pragma mark - Window Backdrop\n\n\n/// Creates a new window backdrop with a given material and frame.\n///\n/// the Window Server will apply the backdrop's material effect to the window using the\n/// application's default connection.\nCG_EXTERN CGSWindowBackdropRef CGSWindowBackdropCreateWithLevel(CGWindowID wid, CFStringRef materialName, CGWindowLevel level, CGRect frame) AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER;\n\n/// Releases a window backdrop object.\nCG_EXTERN void CGSWindowBackdropRelease(CGSWindowBackdropRef backdrop) AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER;\n\n/// Activates the backdrop's effect.  OS X currently only makes the key window's backdrop active.\nCG_EXTERN void CGSWindowBackdropActivate(CGSWindowBackdropRef backdrop) AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER;\nCG_EXTERN void CGSWindowBackdropDeactivate(CGSWindowBackdropRef backdrop) AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER;\n\n/// Sets the saturation of the backdrop.  For certain material types this can imitate the \"vibrancy\" effect in AppKit.\nCG_EXTERN void CGSWindowBackdropSetSaturation(CGSWindowBackdropRef backdrop, CGFloat saturation) AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER;\n\n/// Sets the bleed for the window's backdrop effect.  Vibrant NSWindows use ~0.2.\nCG_EXTERN void CGSWindowSetBackdropBackgroundBleed(CGWindowID wid, CGFloat bleedAmount) AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER;\n\n#endif /* CGS_WINDOW_INTERNAL_H */\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/CGSInternal/CGSWorkspace.h",
    "content": "/*\n * Copyright (C) 2007-2008 Alacatia Labs\n * \n * This software is provided 'as-is', without any express or implied\n * warranty.  In no event will the authors be held liable for any damages\n * arising from the use of this software.\n * \n * Permission is granted to anyone to use this software for any purpose,\n * including commercial applications, and to alter it and redistribute it\n * freely, subject to the following restrictions:\n * \n * 1. The origin of this software must not be misrepresented; you must not\n *    claim that you wrote the original software. If you use this software\n *    in a product, an acknowledgment in the product documentation would be\n *    appreciated but is not required.\n * 2. Altered source versions must be plainly marked as such, and must not be\n *    misrepresented as being the original software.\n * 3. This notice may not be removed or altered from any source distribution.\n * \n * Joe Ranieri joe@alacatia.com\n *\n */\n\n//\n//  Updated by Robert Widmann.\n//  Copyright © 2015-2016 CodaFi. All rights reserved.\n//  Released under the MIT license.\n//\n\n#ifndef CGS_WORKSPACE_INTERNAL_H\n#define CGS_WORKSPACE_INTERNAL_H\n\n#include \"CGSConnection.h\"\n#include \"CGSWindow.h\"\n#include \"CGSTransitions.h\"\n\ntypedef unsigned int CGSWorkspaceID;\n\n/// The space ID given when we're switching spaces.\nstatic const CGSWorkspaceID kCGSTransitioningWorkspaceID = 65538;\n\n/// Gets and sets the current workspace.\nCG_EXTERN CGError CGSGetWorkspace(CGSConnectionID cid, CGSWorkspaceID *outWorkspace);\nCG_EXTERN CGError CGSSetWorkspace(CGSConnectionID cid, CGSWorkspaceID workspace);\n\n/// Transitions to a workspace asynchronously. Note that `duration` is in seconds.\nCG_EXTERN CGError CGSSetWorkspaceWithTransition(CGSConnectionID cid, CGSWorkspaceID workspace, CGSTransitionType transition, CGSTransitionFlags options, CGFloat duration);\n\n/// Gets and sets the workspace for a window.\nCG_EXTERN CGError CGSGetWindowWorkspace(CGSConnectionID cid, CGWindowID wid, CGSWorkspaceID *outWorkspace);\nCG_EXTERN CGError CGSSetWindowWorkspace(CGSConnectionID cid, CGWindowID wid, CGSWorkspaceID workspace);\n\n/// Gets the number of windows in the workspace.\nCG_EXTERN CGError CGSGetWorkspaceWindowCount(CGSConnectionID cid, int workspaceNumber, int *outCount);\nCG_EXTERN CGError CGSGetWorkspaceWindowList(CGSConnectionID cid, int workspaceNumber, int count, CGWindowID *list, int *outCount);\n\n#endif\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/KeyKitC.m",
    "content": "//\n//  CGSKitC.m\n//  \n//\n//  Created by Jiahao Lu on 2022/7/24.\n//\n\n#import <Foundation/Foundation.h>\n"
  },
  {
    "path": "Modules/KeyKit/Sources/KeyKitC/include/KeyKitC.h",
    "content": "//\n//  Header.h\n//  \n//\n//  Created by Jiahao Lu on 2022/7/25.\n//\n\n#ifndef CGSKITC_H\n#define CGSKITC_H\n\n#import <Foundation/Foundation.h>\n#import <IOKit/hidsystem/ev_keymap.h>\n\n#import \"../CGSInternal/CGSInternal.h\"\n\n#endif /* CGSKITC_H */\n"
  },
  {
    "path": "Modules/KeyKit/Tests/KeyKitTests/KeyKitTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import KeyKit\nimport XCTest\n\nfinal class KeyKitTests: XCTestCase {\n    /// The tests below post real keyboard / system-defined events into the OS, which causes\n    /// observable side effects (volume change, Mission Control space switch, stuck modifier\n    /// state in WindowServer, etc.). Gate them behind an env var so day-to-day `swift test`\n    /// stays side-effect free; CI can opt in by setting `RUN_INTEGRATION_TESTS=1`.\n    private func skipUnlessIntegrationEnabled() throws {\n        try XCTSkipUnless(\n            ProcessInfo.processInfo.environment[\"RUN_INTEGRATION_TESTS\"] == \"1\",\n            \"Set RUN_INTEGRATION_TESTS=1 to run KeyKit integration tests that post real system events.\"\n        )\n    }\n\n    func testKeySimulatorInitializesOffMainThread() {\n        let expectation = expectation(description: \"Initialize KeySimulator off the main thread\")\n\n        DispatchQueue.global(qos: .userInitiated).async {\n            _ = KeySimulator()\n            expectation.fulfill()\n        }\n\n        wait(for: [expectation], timeout: 5)\n    }\n\n    func testPressKey() throws {\n        try skipUnlessIntegrationEnabled()\n        let keySimulator = KeySimulator()\n        try keySimulator.press(.home)\n    }\n\n    func testPostSymbolicHotKey() throws {\n        try skipUnlessIntegrationEnabled()\n        try postSymbolicHotKey(.spaceLeft)\n    }\n\n    func testPostSystemDefinedKey() throws {\n        try skipUnlessIntegrationEnabled()\n        postSystemDefinedKey(.soundDown)\n    }\n}\n"
  },
  {
    "path": "Modules/ObservationToken/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/config/registries.json\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n.netrc\n"
  },
  {
    "path": "Modules/ObservationToken/Package.swift",
    "content": "// swift-tools-version: 5.6\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"ObservationToken\",\n    products: [\n        .library(\n            name: \"ObservationToken\",\n            targets: [\"ObservationToken\"]\n        )\n    ],\n    dependencies: [],\n    targets: [\n        .target(\n            name: \"ObservationToken\",\n            dependencies: []\n        ),\n        .testTarget(\n            name: \"ObservationTokenTests\",\n            dependencies: [\"ObservationToken\"]\n        )\n    ]\n)\n"
  },
  {
    "path": "Modules/ObservationToken/README.md",
    "content": "# ObservationToken\n\nAn ObservationToken that can be tied to the specific lifetime.\n"
  },
  {
    "path": "Modules/ObservationToken/Sources/ObservationToken/LifetimeAssociation.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n// https://github.com/sindresorhus/Defaults/blob/54f970b9d7c269193756599c7ae5318878dcab1a/Sources/Defaults/util.swift\n\n/*\n MIT License\n\n Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport Foundation\n\nfinal class AssociatedObject<T: Any> {\n    subscript(index: Any) -> T? {\n        get {\n            objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T?\n        } set {\n            objc_setAssociatedObject(\n                index,\n                Unmanaged.passUnretained(self).toOpaque(),\n                newValue,\n                .OBJC_ASSOCIATION_RETAIN_NONATOMIC\n            )\n        }\n    }\n}\n\n/**\n Causes a given target object to live at least as long as a given owner object.\n */\nfinal class LifetimeAssociation {\n    private class ObjectLifetimeTracker {\n        var object: AnyObject?\n        var deinitHandler: () -> Void\n\n        init(for weaklyHeldObject: AnyObject, deinitHandler: @escaping () -> Void) {\n            object = weaklyHeldObject\n            self.deinitHandler = deinitHandler\n        }\n\n        deinit {\n            deinitHandler()\n        }\n    }\n\n    private static let associatedObjects = AssociatedObject<[ObjectLifetimeTracker]>()\n    private weak var wrappedObject: ObjectLifetimeTracker?\n    private weak var owner: AnyObject?\n\n    /**\n     Causes the given target object to live at least as long as either the given owner object or the resulting `LifetimeAssociation`, whichever is deallocated first.\n     When either the owner or the new `LifetimeAssociation` is destroyed, the given deinit handler, if any, is called.\n     ```\n     class Ghost {\n     var association: LifetimeAssociation?\n     func haunt(_ host: Furniture) {\n     association = LifetimeAssociation(of: self, with: host) { [weak self] in\n     // Host has been deinitialized\n     self?.haunt(seekHost())\n     }\n     }\n     }\n     let piano = Piano()\n     Ghost().haunt(piano)\n     // The Ghost will remain alive as long as `piano` remains alive.\n     ```\n     - Parameter target: The object whose lifetime will be extended.\n     - Parameter owner: The object whose lifetime extends the target object's lifetime.\n     - Parameter deinitHandler: An optional closure to call when either `owner` or the resulting `LifetimeAssociation` is deallocated.\n     */\n    init(of target: AnyObject, with owner: AnyObject, deinitHandler: @escaping () -> Void = {}) {\n        let wrappedObject = ObjectLifetimeTracker(for: target, deinitHandler: deinitHandler)\n\n        let associatedObjects = Self.associatedObjects[owner] ?? []\n        Self.associatedObjects[owner] = associatedObjects + [wrappedObject]\n\n        self.wrappedObject = wrappedObject\n        self.owner = owner\n    }\n\n    /**\n     Invalidates the association, unlinking the target object's lifetime from that of the owner object. The provided deinit handler is not called.\n     */\n    func cancel() {\n        wrappedObject?.deinitHandler = {}\n        invalidate()\n    }\n\n    deinit {\n        invalidate()\n    }\n\n    private func invalidate() {\n        guard\n            let owner,\n            let wrappedObject,\n            var associatedObjects = Self.associatedObjects[owner],\n            let wrappedObjectAssociationIndex = associatedObjects.firstIndex(where: { $0 === wrappedObject })\n        else {\n            return\n        }\n\n        associatedObjects.remove(at: wrappedObjectAssociationIndex)\n        Self.associatedObjects[owner] = associatedObjects\n        self.owner = nil\n    }\n}\n"
  },
  {
    "path": "Modules/ObservationToken/Sources/ObservationToken/ObservationToken.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\npublic final class ObservationToken {\n    private let cancellationClosure: () -> Void\n    private var cancelled = false\n\n    public init(cancellationClosure: @escaping () -> Void) {\n        self.cancellationClosure = cancellationClosure\n    }\n\n    deinit {\n        cancel()\n    }\n\n    private var lifetimeAssociation: LifetimeAssociation?\n\n    @discardableResult\n    public func tieToLifetime(of weaklyHeldObject: AnyObject) -> Self {\n        lifetimeAssociation = LifetimeAssociation(of: self, with: weaklyHeldObject) { [weak self] in\n            self?.cancellationClosure()\n        }\n\n        return self\n    }\n\n    public func removeLifetime() {\n        lifetimeAssociation?.cancel()\n    }\n\n    public func cancel() {\n        guard !cancelled else {\n            return\n        }\n\n        cancelled = true\n        cancellationClosure()\n    }\n}\n"
  },
  {
    "path": "Modules/ObservationToken/Tests/ObservationTokenTests/ObservationTokenTests.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\n@testable import ObservationToken\nimport XCTest\n\nfinal class ObservationTokenTests: XCTestCase {\n    func testCancel() {\n        var cancelled = false\n\n        do {\n            ObservationToken {\n                cancelled = true\n            }\n        }\n\n        XCTAssertTrue(cancelled)\n    }\n\n    func testTieToLifetime() {\n        var cancelled = false\n\n        class A {}\n\n        do {\n            let a = A()\n\n            do {\n                ObservationToken {\n                    cancelled = true\n                }.tieToLifetime(of: a)\n            }\n\n            XCTAssertFalse(cancelled)\n        }\n\n        XCTAssertTrue(cancelled)\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/config/registries.json\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n.netrc\n"
  },
  {
    "path": "Modules/PointerKit/Package.swift",
    "content": "// swift-tools-version: 5.6\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"PointerKit\",\n    products: [\n        .library(\n            name: \"PointerKit\",\n            targets: [\"PointerKit\"]\n        )\n    ],\n    dependencies: [\n        .package(name: \"ObservationToken\", path: \"../ObservationToken\")\n    ],\n    targets: [\n        .target(\n            name: \"PointerKitC\",\n            dependencies: []\n        ),\n        .target(\n            name: \"PointerKit\",\n            dependencies: [\n                \"ObservationToken\",\n                \"PointerKitC\"\n            ]\n        ),\n        .testTarget(\n            name: \"PointerKitTests\",\n            dependencies: [\"PointerKit\"]\n        )\n    ]\n)\n"
  },
  {
    "path": "Modules/PointerKit/README.md",
    "content": "# PointerKit\n\nA package to manipulate pointer devices.\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/Extensions/Comparable+Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nextension Comparable {\n    func clamp(_ x: Self, _ y: Self) -> Self {\n        let low = min(x, y)\n        let high = max(x, y)\n\n        return max(low, min(self, high))\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/Extensions/Dictionary+Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension Dictionary where Key == UUID {\n    mutating func insert(_ value: Value) -> UUID {\n        let id = UUID()\n        self[id] = value\n        return id\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/Extensions/IOHIDElement+Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\npublic extension IOHIDElement {\n    var usagePage: UInt32 {\n        IOHIDElementGetUsagePage(self)\n    }\n\n    var usage: UInt32 {\n        IOHIDElementGetUsage(self)\n    }\n}\n\nextension IOHIDElement: CustomStringConvertible {\n    public var description: String {\n        String(format: \"usagePage: %02X usage: %02X\", usagePage, usage)\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/Extensions/IOHIDServiceClient+Property.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport PointerKitC\n\nextension IOHIDServiceClient {\n    func getProperty<T>(_ key: String) -> T? {\n        guard let valueRef = IOHIDServiceClientCopyProperty(self, key as CFString) else {\n            return nil\n        }\n        guard let value = valueRef as? T else {\n            return nil\n        }\n        return value\n    }\n\n    func setProperty<T>(_ value: T, forKey: String) {\n        IOHIDServiceClientSetProperty(self, forKey as CFString, value as AnyObject)\n    }\n\n    func getPropertyIOFixed(_ key: String) -> Double? {\n        (getProperty(key) as IOFixed?).map { Double($0) / 65_536 }\n    }\n\n    func setPropertyIOFixed(_ value: Double?, forKey: String) {\n        setProperty(value.map { IOFixed($0 * 65_536) }, forKey: forKey)\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/Extensions/IOHIDServiceClient+Service.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\nextension IOHIDServiceClient {\n    private func getService() -> io_service_t? {\n        guard let registryID = IOHIDServiceClientGetRegistryID(self) as? UInt64 else {\n            return nil\n        }\n\n        guard let matching = IORegistryEntryIDMatching(registryID) else {\n            return nil\n        }\n\n        let mainPort: mach_port_t\n        if #available(macOS 12.0, *) {\n            mainPort = kIOMainPortDefault\n        } else {\n            mainPort = kIOMasterPortDefault\n        }\n\n        var service = IOServiceGetMatchingService(mainPort, matching)\n        guard service != 0 else {\n            return nil\n        }\n\n        if IOObjectConformsTo(service, \"IOHIDDevice\") != MACH_PORT_NULL {\n            return service\n        }\n\n        var iter = io_iterator_t()\n        guard IORegistryEntryCreateIterator(\n            service,\n            \"IOService\",\n            IOOptionBits(kIORegistryIterateRecursively | kIORegistryIterateParents),\n            &iter\n        ) == KERN_SUCCESS else {\n            IOObjectRelease(service)\n            return nil\n        }\n        defer { IOObjectRelease(iter) }\n\n        while true {\n            IOObjectRelease(service)\n            service = IOIteratorNext(iter)\n            guard service != MACH_PORT_NULL else {\n                break\n            }\n            if IOObjectConformsTo(service, \"IOHIDDevice\") != 0 {\n                return service\n            }\n        }\n\n        return nil\n    }\n\n    var device: IOHIDDevice? {\n        guard let service = getService() else {\n            return nil\n        }\n        defer { IOObjectRelease(service) }\n        return IOHIDDeviceCreate(kCFAllocatorDefault, service)\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/Extensions/IOHIDValue+Extensions.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\n\npublic extension IOHIDValue {\n    var timestamp: UInt64 {\n        IOHIDValueGetTimeStamp(self)\n    }\n\n    var length: CFIndex {\n        IOHIDValueGetLength(self)\n    }\n\n    var data: Data {\n        Data(bytes: IOHIDValueGetBytePtr(self), count: length)\n    }\n\n    var integerValue: Int {\n        IOHIDValueGetIntegerValue(self)\n    }\n\n    var element: IOHIDElement {\n        IOHIDValueGetElement(self)\n    }\n}\n\nextension IOHIDValue: CustomStringConvertible {\n    public var description: String {\n        \"timestamp: \\(timestamp) length: \\(length) data: \\(data.map(\\.self)) integerValue: \\(integerValue) element=(\\(element))\"\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/PointerDevice.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport ObservationToken\nimport PointerKitC\n\n/// Common IOHID transport names.\n/// This is a shared string namespace, not an exhaustive transport model.\npublic enum PointerDeviceTransportName {\n    public static let usb = \"USB\"\n    public static let bluetooth = \"Bluetooth\"\n    public static let bluetoothLowEnergy = \"Bluetooth Low Energy\"\n}\n\npublic class PointerDevice {\n    let client: IOHIDServiceClient\n    let device: IOHIDDevice?\n\n    public typealias InputValueClosure = (PointerDevice, IOHIDValue) -> Void\n    public typealias InputReportClosure = (PointerDevice, Data) -> Void\n\n    private var inputReportCallbackRegistered = false\n    private var inputReportBuffer: UnsafeMutablePointer<UInt8>?\n    private var inputReportBufferLength = 0\n\n    private let synchronousReportRequestLock = NSLock()\n    private let pendingReportRequestLock = NSLock()\n    private var pendingReportMatcher: ((Data) -> Bool)?\n    private var pendingReportResponse: Data?\n    private var pendingReportSemaphore: DispatchSemaphore?\n\n    private var observations = (\n        inputValue: [UUID: InputValueClosure](),\n        inputReport: [UUID: InputReportClosure](),\n        ()\n    )\n\n    private static let inputValueCallback: IOHIDValueCallback = { context, _, _, value in\n        guard let context else {\n            return\n        }\n        let this = Unmanaged<PointerDevice>.fromOpaque(context).takeUnretainedValue()\n\n        this.inputValueCallback(value)\n    }\n\n    private static let inputReportCallback: IOHIDReportCallback = { context, _, _, _, _, report, reportLength in\n        guard let context else {\n            return\n        }\n        let this = Unmanaged<PointerDevice>.fromOpaque(context).takeUnretainedValue()\n\n        this.inputReportCallback(Data(bytes: report, count: reportLength))\n    }\n\n    init(_ client: IOHIDServiceClient) {\n        self.client = client\n        device = client.device\n\n        if let device {\n            IOHIDDeviceOpen(device, IOOptionBits(kIOHIDOptionsTypeNone))\n            IOHIDDeviceSetInputValueMatching(device, nil)\n            let this = Unmanaged.passUnretained(self).toOpaque()\n            IOHIDDeviceRegisterInputValueCallback(device, Self.inputValueCallback, this)\n            IOHIDDeviceScheduleWithRunLoop(device, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n        }\n    }\n\n    deinit {\n        inputReportBuffer?.deallocate()\n\n        if let device {\n            IOHIDDeviceClose(device, IOOptionBits(kIOHIDOptionsTypeNone))\n            IOHIDDeviceUnscheduleFromRunLoop(device, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)\n        }\n    }\n}\n\nextension PointerDevice: Equatable {\n    public static func == (lhs: PointerDevice, rhs: PointerDevice) -> Bool {\n        lhs.client == rhs.client\n    }\n}\n\nextension PointerDevice: Hashable {\n    public func hash(into hasher: inout Hasher) {\n        hasher.combine(client)\n    }\n}\n\n// MARK: Product and vendor information\n\npublic extension PointerDevice {\n    var product: String? {\n        client.getProperty(kIOHIDProductKey)\n    }\n\n    var name: String {\n        product ?? \"(unknown)\"\n    }\n\n    var vendorID: Int? {\n        client.getProperty(kIOHIDVendorIDKey)\n    }\n\n    var productID: Int? {\n        client.getProperty(kIOHIDProductIDKey)\n    }\n\n    var vendorIDString: String {\n        guard let vendorID else {\n            return \"(nil)\"\n        }\n\n        return String(format: \"0x%04X\", vendorID)\n    }\n\n    var productIDString: String {\n        guard let productID else {\n            return \"(nil)\"\n        }\n\n        return String(format: \"0x%04X\", productID)\n    }\n\n    var serialNumber: String? {\n        client.getProperty(kIOHIDSerialNumberKey)\n    }\n\n    var buttonCount: Int? {\n        client.getProperty(kIOHIDPointerButtonCountKey)\n    }\n\n    var locationID: Int? {\n        client.getProperty(\"LocationID\")\n    }\n\n    var primaryUsagePage: Int? {\n        client.getProperty(\"PrimaryUsagePage\")\n    }\n\n    var primaryUsage: Int? {\n        client.getProperty(\"PrimaryUsage\")\n    }\n\n    var maxInputReportSize: Int? {\n        client.getProperty(\"MaxInputReportSize\")\n    }\n\n    var maxOutputReportSize: Int? {\n        client.getProperty(\"MaxOutputReportSize\")\n    }\n\n    var maxFeatureReportSize: Int? {\n        client.getProperty(\"MaxFeatureReportSize\")\n    }\n\n    var transport: String? {\n        client.getProperty(\"Transport\")\n    }\n}\n\nextension PointerDevice: CustomStringConvertible {\n    public var description: String {\n        String(format: \"%@ (VID=%@, PID=%@)\", name, vendorIDString, productIDString)\n    }\n}\n\n// MARK: Pointer resolution and acceleration\n\npublic extension PointerDevice {\n    /**\n     Indicates the pointer resolution.\n     The lower the value is, the faster the pointer moves.\n\n     This value is in the range [10-1995].\n     */\n    var pointerResolution: Double? {\n        get { client.getPropertyIOFixed(kIOHIDPointerResolutionKey) }\n\n        set {\n            client.setPropertyIOFixed(newValue.map { $0.clamp(10, 1995) }, forKey: kIOHIDPointerResolutionKey)\n\n            // HACK: Trigger a `pointerAcceleration` change to make `pointerResolution` take affect\n            pointerAcceleration = pointerAcceleration\n        }\n    }\n\n    var pointerAccelerationType: String? {\n        get {\n            if let pointerAccelerationType = client.getProperty(kIOHIDPointerAccelerationTypeKey) as String? {\n                return pointerAccelerationType\n            }\n\n            // Guess the type...\n\n            if (client.getProperty(kIOHIDPointerAccelerationKey) as IOFixed?) != nil {\n                return kIOHIDPointerAccelerationKey\n            }\n\n            return kIOHIDMouseAccelerationTypeKey\n        }\n\n        set {\n            client.setProperty(newValue, forKey: kIOHIDPointerAccelerationKey)\n        }\n    }\n\n    var useLinearScalingMouseAcceleration: Int? {\n        get {\n            // TODO: Use `kIOHIDUseLinearScalingMouseAccelerationKey`.\n            client.getProperty(\"HIDUseLinearScalingMouseAcceleration\")\n        }\n        set {\n            // TODO: Use `kIOHIDUseLinearScalingMouseAccelerationKey`.\n            client.setProperty(newValue, forKey: \"HIDUseLinearScalingMouseAcceleration\")\n        }\n    }\n\n    /**\n     Indicates the pointer acceleration.\n\n     This value is in the range [0, 20] ∪ { -1 }. -1 means acceleration and sensitivity are disabled.\n     */\n    var pointerAcceleration: Double? {\n        get {\n            if useLinearScalingMouseAcceleration == 1 {\n                return -1\n            }\n            return client.getPropertyIOFixed(pointerAccelerationType ?? kIOHIDMouseAccelerationTypeKey)\n        }\n\n        set {\n            client.setPropertyIOFixed(\n                newValue.map { $0 == -1 ? $0 : $0.clamp(0, 20) },\n                forKey: pointerAccelerationType ?? kIOHIDMouseAccelerationTypeKey\n            )\n        }\n    }\n}\n\n// MARK: Observe input events\n\nextension PointerDevice {\n    private func inputValueCallback(_ value: IOHIDValue) {\n        for (_, callback) in observations.inputValue {\n            callback(self, value)\n        }\n    }\n\n    public func observeInput(using closure: @escaping InputValueClosure) -> ObservationToken {\n        let id = observations.inputValue.insert(closure)\n\n        return ObservationToken { [weak self] in\n            self?.observations.inputValue.removeValue(forKey: id)\n        }\n    }\n}\n\n// MARK: Observe input reports\n\nextension PointerDevice {\n    private func inputReportCallback(_ report: Data) {\n        completePendingReportRequest(with: report)\n\n        for (_, callback) in observations.inputReport {\n            callback(self, report)\n        }\n    }\n\n    private func completePendingReportRequest(with report: Data) {\n        pendingReportRequestLock.lock()\n        defer { pendingReportRequestLock.unlock() }\n\n        guard let reportMatcher = pendingReportMatcher, reportMatcher(report) else {\n            return\n        }\n\n        pendingReportResponse = report\n        pendingReportMatcher = nil\n        pendingReportSemaphore?.signal()\n    }\n\n    private func clearPendingReportRequest() {\n        pendingReportMatcher = nil\n        pendingReportResponse = nil\n        pendingReportSemaphore = nil\n    }\n\n    func ensureInputReportCallbackRegistered(minimumReportLength: Int = 0) {\n        guard let device else {\n            return\n        }\n\n        let desiredReportLength = max(maxInputReportSize ?? 8, minimumReportLength, 8)\n        if inputReportBufferLength < desiredReportLength {\n            let newBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: desiredReportLength)\n            inputReportBuffer?.deallocate()\n            inputReportBuffer = newBuffer\n            inputReportBufferLength = desiredReportLength\n            inputReportCallbackRegistered = false\n        }\n\n        guard !inputReportCallbackRegistered, let inputReportBuffer else {\n            return\n        }\n\n        let this = Unmanaged.passUnretained(self).toOpaque()\n        IOHIDDeviceRegisterInputReportCallback(\n            device,\n            inputReportBuffer,\n            inputReportBufferLength,\n            Self.inputReportCallback,\n            this\n        )\n        inputReportCallbackRegistered = true\n    }\n\n    public func performSynchronousOutputReportRequest(\n        _ report: Data,\n        timeout: TimeInterval,\n        matching: @escaping (Data) -> Bool\n    ) -> Data? {\n        guard let device, !report.isEmpty else {\n            return nil\n        }\n\n        synchronousReportRequestLock.lock()\n        defer { synchronousReportRequestLock.unlock() }\n\n        ensureInputReportCallbackRegistered(minimumReportLength: max(report.count, maxInputReportSize ?? 0))\n\n        let semaphore = DispatchSemaphore(value: 0)\n        pendingReportRequestLock.lock()\n        clearPendingReportRequest()\n        pendingReportMatcher = matching\n        pendingReportSemaphore = semaphore\n        pendingReportRequestLock.unlock()\n\n        let result = report.withUnsafeBytes { rawBuffer -> IOReturn in\n            guard let baseAddress = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {\n                return kIOReturnBadArgument\n            }\n\n            return IOHIDDeviceSetReport(\n                device,\n                kIOHIDReportTypeOutput,\n                CFIndex(report[0]),\n                baseAddress,\n                report.count\n            )\n        }\n\n        guard result == kIOReturnSuccess else {\n            pendingReportRequestLock.lock()\n            clearPendingReportRequest()\n            pendingReportRequestLock.unlock()\n            return nil\n        }\n\n        if Thread.isMainThread {\n            let deadline = Date().addingTimeInterval(timeout)\n            while Date() < deadline {\n                pendingReportRequestLock.lock()\n                let response = pendingReportResponse\n                pendingReportRequestLock.unlock()\n\n                if response != nil {\n                    break\n                }\n\n                CFRunLoopRunInMode(.defaultMode, 0.01, true)\n            }\n        } else {\n            _ = semaphore.wait(timeout: .now() + timeout)\n        }\n\n        pendingReportRequestLock.lock()\n        let response = pendingReportResponse\n        clearPendingReportRequest()\n        pendingReportRequestLock.unlock()\n        return response\n    }\n\n    public func observeReport(using closure: @escaping InputReportClosure) -> ObservationToken {\n        ensureInputReportCallbackRegistered()\n\n        let id = observations.inputReport.insert(closure)\n\n        return ObservationToken { [weak self] in\n            self?.observations.inputReport.removeValue(forKey: id)\n        }\n    }\n}\n\n// MARK: Utilities\n\npublic extension PointerDevice {\n    func confirmsTo(_ usagePage: Int, _ usage: Int) -> Bool {\n        IOHIDServiceClientConformsTo(client, UInt32(usagePage), UInt32(usage)) != 0\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKit/PointerDeviceManager.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport Foundation\nimport ObservationToken\nimport PointerKitC\n\npublic final class PointerDeviceManager {\n    private var eventSystemClient: IOHIDEventSystemClient?\n\n    public typealias DeviceAddedClosure = (PointerDeviceManager, PointerDevice) -> Void\n    public typealias DeviceRemovedClosure = (PointerDeviceManager, PointerDevice) -> Void\n    public typealias PropertyChangedClosure = (PointerDeviceManager) -> Void\n    public typealias EventReceivedClosure = (PointerDeviceManager, PointerDevice, IOHIDEvent) -> Void\n\n    private var observations = (\n        deviceAdded: [UUID: DeviceAddedClosure](),\n        deviceRemoved: [UUID: DeviceRemovedClosure](),\n        propertyChanged: [UUID: (property: String, closure: PropertyChangedClosure)](),\n        eventReceived: [UUID: EventReceivedClosure]()\n    )\n\n    private var serviceClientToPointerDevice = [IOHIDServiceClient: PointerDevice]()\n\n    public var devices: [PointerDevice] {\n        Array(serviceClientToPointerDevice.values)\n    }\n\n    public init() {}\n}\n\n// MARK: Observation API\n\npublic extension PointerDeviceManager {\n    func observeDeviceAdded(using closure: @escaping DeviceAddedClosure) -> ObservationToken {\n        let id = observations.deviceAdded.insert(closure)\n\n        return ObservationToken { [weak self] in\n            self?.observations.deviceAdded.removeValue(forKey: id)\n        }\n    }\n\n    func observeDeviceRemoved(using closure: @escaping DeviceRemovedClosure) -> ObservationToken {\n        let id = observations.deviceRemoved.insert(closure)\n\n        return ObservationToken { [weak self] in\n            self?.observations.deviceRemoved.removeValue(forKey: id)\n        }\n    }\n\n    func observePropertyChanged(\n        property: String,\n        using closure: @escaping PropertyChangedClosure\n    ) -> ObservationToken {\n        let id = observations.propertyChanged.insert((property: property, closure: closure))\n\n        return ObservationToken { [weak self] in\n            self?.observations.propertyChanged.removeValue(forKey: id)\n        }\n    }\n\n    func observeEventReceived(using closure: @escaping EventReceivedClosure) -> ObservationToken {\n        let id = observations.eventReceived.insert(closure)\n\n        return ObservationToken { [weak self] in\n            self?.observations.eventReceived.removeValue(forKey: id)\n        }\n    }\n}\n\n// MARK: Device observation\n\nextension PointerDeviceManager {\n    private enum ObservationMatches {\n        static var mouseOrPointer: CFArray {\n            let usageMouse = [\n                kIOHIDDeviceUsagePageKey: kHIDPage_GenericDesktop,\n                kIOHIDDeviceUsageKey: kHIDUsage_GD_Mouse\n            ] as CFDictionary\n\n            let usagePointer = [\n                kIOHIDDeviceUsagePageKey: kHIDPage_GenericDesktop,\n                kIOHIDDeviceUsageKey: kHIDUsage_GD_Pointer\n            ] as CFDictionary\n\n            return [usageMouse, usagePointer] as CFArray\n        }\n    }\n\n    private static let propertyChangedCallback: IOHIDEventSystemClientPropertyChangedCallback =\n        { target, _, property, value in\n            guard let target else {\n                return\n            }\n            guard let property else {\n                return\n            }\n\n            let this = Unmanaged<PointerDeviceManager>.fromOpaque(target).takeUnretainedValue()\n            this.propertyChangedCallback(property as String, value)\n        }\n\n    /**\n     Start observing device additions and removals.\n\n     Registered `DeviceAddedClosure`s will be notified immediately with all the current devices.\n     */\n    public func startObservation() {\n        guard eventSystemClient == nil else {\n            return\n        }\n\n        guard let eventSystemClient = IOHIDEventSystemClientCreate(kCFAllocatorDefault) else {\n            return\n        }\n\n        self.eventSystemClient = eventSystemClient\n\n        IOHIDEventSystemClientSetMatchingMultiple(\n            eventSystemClient,\n            ObservationMatches.mouseOrPointer\n        )\n        IOHIDEventSystemClientRegisterDeviceMatchingBlock(\n            eventSystemClient,\n            serviceMatchingCallback,\n            nil,\n            nil\n        )\n        IOHIDEventSystemClientRegisterEventBlock(\n            eventSystemClient,\n            eventReceivedCallback,\n            nil,\n            nil\n        )\n        IOHIDEventSystemClientScheduleWithDispatchQueue(eventSystemClient, DispatchQueue.main)\n\n        if let clients = IOHIDEventSystemClientCopyServices(eventSystemClient) as? [IOHIDServiceClient] {\n            for client in clients {\n                addDevice(forClient: client)\n            }\n        }\n\n        for property in observations.propertyChanged.values.map(\\.property) {\n            IOHIDEventSystemClientRegisterPropertyChangedCallback(\n                eventSystemClient,\n                property as CFString,\n                Self.propertyChangedCallback,\n                Unmanaged.passUnretained(self).toOpaque(),\n                nil\n            )\n        }\n    }\n\n    /**\n     Stop observing device additions and removals.\n\n     Registered `DeviceRemovedClosure`s will be notified immediately with all the current devices.\n     */\n    public func stopObservation() {\n        guard let eventSystemClient else {\n            return\n        }\n\n        IOHIDEventSystemClientUnregisterDeviceMatchingBlock(eventSystemClient)\n        IOHIDEventSystemClientUnscheduleFromDispatchQueue(eventSystemClient, DispatchQueue.main)\n\n        for device in devices {\n            removeDevice(device)\n        }\n\n        self.eventSystemClient = nil\n    }\n\n    private func serviceMatchingCallback(\n        _: UnsafeMutableRawPointer?,\n        _: UnsafeMutableRawPointer?,\n        _ client: IOHIDServiceClient?\n    ) {\n        guard let client else {\n            return\n        }\n\n        addDevice(forClient: client)\n    }\n\n    private func clientRemovalCallback(\n        _: UnsafeMutableRawPointer?,\n        _: UnsafeMutableRawPointer?,\n        _ client: IOHIDServiceClient?\n    ) {\n        guard let client else {\n            return\n        }\n\n        removeDevice(forClient: client)\n    }\n\n    private func eventReceivedCallback(\n        _: UnsafeMutableRawPointer?,\n        _: UnsafeMutableRawPointer?,\n        _ client: IOHIDServiceClient?,\n        event: IOHIDEvent?\n    ) {\n        guard let client else {\n            return\n        }\n        guard let event else {\n            return\n        }\n\n        guard let device = serviceClientToPointerDevice[client] else {\n            return\n        }\n\n        for (_, callback) in observations.eventReceived {\n            callback(self, device, event)\n        }\n    }\n\n    private func propertyChangedCallback(_ property: String, _: AnyObject?) {\n        for (_, (observingProperty, callback)) in observations.propertyChanged where property == observingProperty {\n            callback(self)\n        }\n    }\n\n    private func addDevice(forClient client: IOHIDServiceClient) {\n        guard serviceClientToPointerDevice[client] == nil else {\n            return\n        }\n\n        let device = PointerDevice(client)\n\n        serviceClientToPointerDevice[client] = device\n\n        for (_, callback) in observations.deviceAdded {\n            callback(self, device)\n        }\n\n        IOHIDServiceClientRegisterRemovalBlock(client, clientRemovalCallback, nil, nil)\n    }\n\n    private func removeDevice(forClient client: IOHIDServiceClient) {\n        guard let device = serviceClientToPointerDevice[client] else {\n            return\n        }\n\n        removeDevice(device)\n    }\n\n    private func removeDevice(_ device: PointerDevice) {\n        serviceClientToPointerDevice.removeValue(forKey: device.client)\n\n        for (_, callback) in observations.deviceRemoved {\n            callback(self, device)\n        }\n    }\n\n    public func pointerDeviceFromIOHIDEvent(_ ioHidEvent: IOHIDEvent) -> PointerDevice? {\n        guard let eventSystemClient else {\n            return nil\n        }\n\n        let senderID = IOHIDEventGetSenderID(ioHidEvent)\n        let serviceClient = IOHIDEventSystemClientCopyServiceForRegistryID(eventSystemClient, senderID)\n        return serviceClient.flatMap { serviceClientToPointerDevice[$0] }\n    }\n}\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKitC/PointerKitC.m",
    "content": "//\n//  PointerKitSPI.m\n//  \n//\n//  Created by Jiahao Lu on 2022/6/13.\n//\n\n#import <Foundation/Foundation.h>\n"
  },
  {
    "path": "Modules/PointerKit/Sources/PointerKitC/include/IOKitSPIMac.h",
    "content": "/*\n * Copyright (C) 2020 Apple Inc. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef IOKITSPIMAC_H\n#define IOKITSPIMAC_H\n\n#import <IOKit/hid/IOHIDDevice.h>\n#import <IOKit/hid/IOHIDManager.h>\n#import <IOKit/hid/IOHIDUsageTables.h>\n\n#define kIOHIDVendorIDKey \"VendorID\"\n#define kIOHIDProductIDKey \"ProductID\"\n\nCF_IMPLICIT_BRIDGING_ENABLED\n\ntypedef CFTypeRef IOHIDEventRef;\ntypedef struct CF_BRIDGED_TYPE(id) __IOHIDServiceClient * IOHIDServiceClientRef;\ntypedef struct CF_BRIDGED_TYPE(id) __IOHIDEventSystemClient * IOHIDEventSystemClientRef;\ntypedef void (^IOHIDServiceClientBlock)(void *, void *, IOHIDServiceClientRef);\n\ntypedef CF_ENUM(int, IOHIDEventSystemClientType)\n{\n    kIOHIDEventSystemClientTypeAdmin,\n    kIOHIDEventSystemClientTypeMonitor,\n    kIOHIDEventSystemClientTypePassive,\n    kIOHIDEventSystemClientTypeRateControlled,\n    kIOHIDEventSystemClientTypeSimple\n};\n\nIOHIDEventSystemClientRef IOHIDEventSystemClientCreateWithType(CFAllocatorRef, IOHIDEventSystemClientType, CFDictionaryRef);\nIOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef);\nvoid IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef, CFDictionaryRef);\nvoid IOHIDEventSystemClientSetMatchingMultiple(IOHIDEventSystemClientRef, CFArrayRef);\nIOHIDServiceClientRef IOHIDEventSystemClientCopyServiceForRegistryID(IOHIDEventSystemClientRef, uint64_t registryID);\nvoid IOHIDEventSystemClientRegisterDeviceMatchingBlock(IOHIDEventSystemClientRef, IOHIDServiceClientBlock, void *, void *);\nvoid IOHIDEventSystemClientUnregisterDeviceMatchingBlock(IOHIDEventSystemClientRef);\nvoid IOHIDEventSystemClientScheduleWithDispatchQueue(IOHIDEventSystemClientRef, dispatch_queue_t);\nvoid IOHIDEventSystemClientUnscheduleFromDispatchQueue(IOHIDEventSystemClientRef, dispatch_queue_t);\nvoid IOHIDEventSystemClientSetDispatchQueue(IOHIDEventSystemClientRef, dispatch_queue_t);\nvoid IOHIDEventSystemClientActivate(IOHIDEventSystemClientRef);\n\nvoid IOHIDServiceClientRegisterRemovalBlock(IOHIDServiceClientRef, IOHIDServiceClientBlock, void*, void*);\n\ntypedef void (*IOHIDEventSystemClientPropertyChangedCallback)(void* target, void* context, CFStringRef property, CFTypeRef value);\nvoid IOHIDEventSystemClientRegisterPropertyChangedCallback(IOHIDEventSystemClientRef client, CFStringRef property, IOHIDEventSystemClientPropertyChangedCallback callback, void* target, void *context);\n\nCFTypeRef IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef key);\n\nenum {\n    kIOHIDEventTypeNULL,\n    kIOHIDEventTypeVendorDefined,\n    kIOHIDEventTypeKeyboard = 3,\n    kIOHIDEventTypeRotation = 5,\n    kIOHIDEventTypeScroll = 6,\n    kIOHIDEventTypeZoom = 8,\n    kIOHIDEventTypeDigitizer = 11,\n    kIOHIDEventTypeNavigationSwipe = 16,\n    kIOHIDEventTypeForce = 32,\n};\ntypedef uint32_t IOHIDEventType;\n\ntypedef uint32_t IOHIDEventField;\ntypedef uint64_t IOHIDEventSenderID;\n\n\nenum {\n    kIOHIDEventScrollMomentumInterrupted = (1 << 4),\n};\ntypedef uint8_t IOHIDEventScrollMomentumBits;\n\n#ifdef __LP64__\ntypedef double IOHIDFloat;\n#else\ntypedef float IOHIDFloat;\n#endif\n\n#define IOHIDEventFieldBase(type) (type << 16)\n\n#define kIOHIDEventFieldScrollBase IOHIDEventFieldBase(kIOHIDEventTypeScroll)\n//static const IOHIDEventField kIOHIDEventFieldScrollX = (kIOHIDEventFieldScrollBase | 0);\n//static const IOHIDEventField kIOHIDEventFieldScrollY = (kIOHIDEventFieldScrollBase | 1);\n\nuint64_t IOHIDEventGetTimeStamp(IOHIDEventRef);\nIOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef, IOHIDEventField);\nIOHIDEventSenderID IOHIDEventGetSenderID(IOHIDEventRef);\nIOHIDEventScrollMomentumBits IOHIDEventGetScrollMomentum(IOHIDEventRef);\n\ntypedef void (^IOHIDEventSystemClientEventBlock)(void* target, void* refcon, IOHIDServiceClientRef sender, IOHIDEventRef event);\nvoid IOHIDEventSystemClientRegisterEventBlock(IOHIDEventSystemClientRef client, IOHIDEventSystemClientEventBlock callback, void* target, void* refcon);\n\nCF_IMPLICIT_BRIDGING_DISABLED\n\n#endif // IOKITSPIMAC_H\n"
  },
  {
    "path": "Modules/PointerKit/Tests/PointerKitTests/PointerDeviceManagerTest.swift",
    "content": "// MIT License\n// Copyright (c) 2021-2026 LinearMouse\n\nimport ObservationToken\n@testable import PointerKit\nimport XCTest\n\nfinal class PointerDeviceManagerTest: XCTestCase {\n    private class Scope {}\n\n    private struct WeakRef<T: AnyObject> {\n        weak var value: T?\n    }\n\n    func testStartStop() {\n        var tokenRef = WeakRef<ObservationToken>()\n\n        do {\n            let manager = PointerDeviceManager()\n\n            // Tieing to manager itself would cause a reference cycle\n            let scope = Scope()\n\n            DispatchQueue.main.async {\n                tokenRef.value = manager.observeDeviceAdded { manager, device in\n                    debugPrint(\"device added\", manager, device)\n                }\n                .tieToLifetime(of: scope)\n\n                manager.observeDeviceRemoved { manager, device in\n                    debugPrint(\"device removed\", manager, device)\n                }\n                .tieToLifetime(of: scope)\n\n                manager.startObservation()\n            }\n\n            DispatchQueue.main.async {\n                manager.stopObservation()\n\n                debugPrint(\"stopped\")\n\n                Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { _ in\n                    debugPrint(\"restarted\")\n\n                    manager.startObservation()\n                }\n            }\n\n            CFRunLoopRunInMode(.defaultMode, 10, false)\n\n            XCTAssertNotNil(tokenRef.value)\n        }\n\n        XCTAssertNil(tokenRef.value)\n    }\n\n    func testPointerResolutionAndPointerAcceleration() {\n        let manager = PointerDeviceManager()\n\n        manager.startObservation()\n\n        DispatchQueue.main.async {\n            for device in manager.devices {\n                print(\"Device:\", device.name)\n                print(\"Pointer resolution:\", device.pointerResolution ?? \"(nil)\")\n                print(\"Pointer acceleration type:\", device.pointerAccelerationType ?? \"(nil)\")\n                print(\"Pointer acceleration:\", device.pointerAcceleration ?? \"(nil)\")\n                print(\"Use linear scaling mouse acceleration:\", device.useLinearScalingMouseAcceleration ?? \"(nil)\")\n                print(\"==========================\")\n            }\n        }\n\n        CFRunLoopRunInMode(.defaultMode, 10, true)\n    }\n}\n"
  },
  {
    "path": "Modules/README.md",
    "content": "# Modules\n\nInternal modules.\n"
  },
  {
    "path": "README-cn.md",
    "content": "<h1 align=\"center\">\n  <a href=\"https://linearmouse.cn\">\n    <img src=\"logo.svg\" width=\"128\" height=\"128\" />\n    <br />\n    LinearMouse\n  </a>\n</h1>\n\n<p align=\"center\">\n  <a href=\"https://github.com/linearmouse/linearmouse/releases/latest\"><img alt=\"GitHub release (latest SemVer)\" src=\"https://img.shields.io/github/v/release/linearmouse/linearmouse?sort=semver\"></a>\n  <a href=\"https://github.com/linearmouse/linearmouse/releases/latest/download/LinearMouse.dmg\"><img src=\"https://img.shields.io/github/downloads/linearmouse/linearmouse/total\" alt=\"Downloads\" /></a>\n  <img src=\"https://img.shields.io/github/license/linearmouse/linearmouse\" alt=\"MIT License\" />\n  <a href=\"https://crowdin.com/project/linearmouse\"><img src=\"https://badges.crowdin.net/linearmouse/localized.svg\" alt=\"Crowdin\" /></a>\n</p>\n\n<p align=\"center\">\nMac 下的鼠标和触控板实用工具。\n</p>\n\n## 开始\n\n请访问 <https://linearmouse.cn>。\n\n## 贡献\n\n在创建拉取请求之前，请阅读[贡献指南](CONTRIBUTING-cn.md)。\n\n## 帮助翻译\n\n请注册 Crowdin 账号并加入我们的 [Crowdin 项目](https://crowdin.com/project/linearmouse)，将 LinearMouse 翻译成支持的语言。推荐使用 GitHub 账号注册，这样我在合并拉取请求时可以把你加入协作者中。\n\n如果你想增加新语言，请[创建一个 issue](https://github.com/linearmouse/linearmouse/issues/new)，我很乐意启用该语言。\n\n我的母语不是英语，所以如果你发现了任何英语本地化的问题，随时欢迎[创建拉取请求](https://github.com/linearmouse/linearmouse/edit/main/LinearMouse/en.lproj/Localizable.strings)来更正我。\n\n## 赞助者\n\n请访问 <https://go.linearmouse.cn/donate>。\n\n## Credits\n\n- [Mac Mouse Fix](https://github.com/noah-nuebling/mac-mouse-fix) - 修改指针速度（灵敏度）的方法由 Mac Mouse Fix 启发。\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n  <a href=\"https://linearmouse.app\">\n    <img src=\"logo.svg\" width=\"128\" height=\"128\" />\n    <br />\n    LinearMouse\n  </a>\n</h1>\n\n<p align=\"center\">\n  <a href=\"https://github.com/linearmouse/linearmouse/releases/latest\"><img alt=\"GitHub release (latest SemVer)\" src=\"https://img.shields.io/github/v/release/linearmouse/linearmouse?sort=semver\"></a>\n  <a href=\"https://github.com/linearmouse/linearmouse/releases/latest/download/LinearMouse.dmg\"><img src=\"https://img.shields.io/github/downloads/linearmouse/linearmouse/total\" alt=\"Downloads\" /></a>\n  <img src=\"https://img.shields.io/github/license/linearmouse/linearmouse\" alt=\"MIT License\" />\n  <a href=\"https://crowdin.com/project/linearmouse\"><img src=\"https://badges.crowdin.net/linearmouse/localized.svg\" alt=\"Crowdin\" /></a>\n</p>\n\n<p align=\"center\">\nThe mouse and trackpad utility for Mac.\n</p>\n\n## Get started\n\nPlease visit https://linearmouse.app.\n\n## Contribute\n\nPlease read the [contributing guide](CONTRIBUTING.md) before making a pull request.\n\n## Help translate\n\nPlease sign up for Crowdin and join our [Crowdin project](https://crowdin.com/project/linearmouse) to translate LinearMouse into supported languages. It is recommended to sign in Crowdin using GitHub, so that I can add you as a co-author when I merge the pull request.\n\nIf you want to add a new language, please [create a new issue](https://github.com/linearmouse/linearmouse/issues/new) and I will be happy to enable that language for you to translate.\n\nI'm not a native English speaker, so if you find any English localization issues, feel free to correct me by [creating a pull request](https://github.com/linearmouse/linearmouse/edit/main/LinearMouse/en.lproj/Localizable.strings).\n\n## Sponsors\n\nPlease visit https://go.linearmouse.app/donate.\n\n## Credits\n\n- [Mac Mouse Fix](https://github.com/noah-nuebling/mac-mouse-fix) - The way to modify the pointer speed (sensitivity) is inspired by Mac Mouse Fix.\n"
  },
  {
    "path": "Scripts/configure-code-signing",
    "content": "#!/bin/bash -e\n\npushd $(dirname \"$0\") > /dev/null\ncd ..\ncp Signing.xcconfig{.tpl,}\npopd > /dev/null\n\nno_available_code_signing_certificate() {\n    echo 'No available code signing certificate. Use ad-hoc certificate.' >&2\n    echo 'If you want to use your own certificate, create a signing certificate in Xcode (https://help.apple.com/xcode/mac/current/#/dev154b28f09) and re-run this command.' >&2\n    exit 0\n}\n\nsearch_code_signing_certificate() {\n    CN=$(security find-identity -vp codesigning | grep \"$1\" | head -1 | awk -F\\\" '{ print $2 }')\n    if [[ -n \"$CN\" ]]; then\n        echo \"Found CN: $CN\" >&2\n        DEVELOPMENT_TEAM=$(certtool y | grep \"$CN\" -A2 | grep OrgUnit | head -1 | awk -F': ' '{ print $2 }')\n        if [[ -z \"$DEVELOPMENT_TEAM\" ]]; then\n            no_available_code_signing_certificate\n        fi\n        CODE_SIGN_IDENTITY=\"$1\"\n    fi\n}\n\nif [[ -z \"$DEVELOPMENT_TEAM\" ]]; then\n    search_code_signing_certificate \"Developer ID Application\"\nfi\nif [[ -z \"$DEVELOPMENT_TEAM\" ]]; then\n    search_code_signing_certificate \"Apple Development\"\nfi\nif [[ -z \"$DEVELOPMENT_TEAM\" ]]; then\n    no_available_code_signing_certificate\nfi\n\npushd $(dirname \"$0\") > /dev/null\ncd ..\ncp Signing.xcconfig{.tpl,}\nsed -i '' \"s/DEVELOPMENT_TEAM =/DEVELOPMENT_TEAM = $DEVELOPMENT_TEAM/\" Signing.xcconfig\nif [[ -n \"$CODE_SIGN_IDENTITY\" ]]; then\n    echo \"CODE_SIGN_IDENTITY = $CODE_SIGN_IDENTITY\" >> Signing.xcconfig\nfi\npopd > /dev/null\n\necho \"DEVELOPMENT_TEAM is configured to $DEVELOPMENT_TEAM.\" >&2\nif [[ -n \"$CODE_SIGN_IDENTITY\" ]]; then\n    echo \"CODE_SIGN_IDENTITY is configured to $CODE_SIGN_IDENTITY\" >&2\nfi\n"
  },
  {
    "path": "Scripts/configure-release",
    "content": "#!/bin/bash -e\n\npushd $(dirname \"$0\") > /dev/null\ncd ..\necho \"PRODUCT_BUNDLE_IDENTIFIER = com.lujjjh.LinearMouse\" >> Release.xcconfig\necho \"ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon\" >> Release.xcconfig\npopd\n"
  },
  {
    "path": "Scripts/configure-version",
    "content": "#!/bin/bash -e\n\nVERSION=$(echo ${GITHUB_REF#refs/tags/v} | grep '^\\d' || echo \"sha-$(git rev-parse --short HEAD)\")\n\npushd $(dirname \"$0\") > /dev/null\ncd ..\necho \"CURRENT_PROJECT_VERSION = $VERSION\" >> Version.xcconfig\npopd\n"
  },
  {
    "path": "Scripts/pre-commit",
    "content": "#!/bin/bash -e\n\nnpm run generate:json-schema\ngit add Documentation/Configuration.json\n\nFILES=$(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\\\ |g' | { grep '.swift$' || :; })\n\n[ -z \"$FILES\" ] && exit 0\n\necho $FILES | xargs swiftformat\necho $FILES | xargs swiftlint --fix\n\necho $FILES | xargs git add\n"
  },
  {
    "path": "Scripts/sign-and-notarize",
    "content": "#!/bin/bash -e\n\nDMG_FILE=\"build/LinearMouse.dmg\"\n\ncd $(dirname \"$0\")\ncd ..\n\nif [[ -z \"$APPLE_ID\" ]]; then\n    echo \"APPLE_ID not specified\" >&2\n    exit 1\nfi\n\nif [[ -z \"$NOTARIZATION_PASSWORD\" ]]; then\n    echo \"NOTARIZATION_PASSWORD not specified\" >&2\n    exit 1\nfi\n\nif [[ -z \"$DEVELOPMENT_TEAM\" ]]; then\n    DEVELOPMENT_TEAM=$(grep 'DEVELOPMENT_TEAM = ' Signing.xcconfig | head -1 | sed 's/^DEVELOPMENT_TEAM = //')\nfi\n\nif [[ -z \"$DEVELOPMENT_TEAM\" ]]; then\n    echo \"DEVELOPMENT_TEAM not specified\" >&2\n    exit 1\nfi\n\nif [ ! -f \"$DMG_FILE\" ]; then\n    echo \"$DMG_FILE not found\" >&2\n    exit 1\nfi\n\necho \"Code signing $DMG_FILE...\"\n\ncodesign -fs \"$DEVELOPMENT_TEAM\" \"$DMG_FILE\"\n\necho \"Notarizing $DMG_FILE...\"\n\nRESULT=$(xcrun notarytool submit \"$DMG_FILE\" --apple-id \"$APPLE_ID\" --password \"$NOTARIZATION_PASSWORD\" --team-id \"$DEVELOPMENT_TEAM\" \\\n    --wait --timeout 2h --output-format json)\n\necho \"$RESULT\" | jq .\n\nSTATUS=$(echo \"$RESULT\" | jq -r .status)\n\nif [ \"$STATUS\" != \"Accepted\" ]; then\n    exit 1\nfi\n\necho \"Stapling $DMG_FILE...\"\n\nxcrun stapler staple $DMG_FILE\n"
  },
  {
    "path": "Scripts/translate-xcstrings.mjs",
    "content": "#!/usr/bin/env node\n\nimport fs from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { spawn } from 'node:child_process'\nimport OpenAI from 'openai'\nimport { DOMParser, XMLSerializer } from '@xmldom/xmldom'\n\nconst DEFAULT_PROJECT_PATH = 'LinearMouse.xcodeproj'\nconst DEFAULT_BASE_URL = 'https://openrouter.ai/api/v1'\nconst DEFAULT_MODEL = 'openai/gpt-4.1-mini'\nconst DEFAULT_BATCH_SIZE = 25\nconst DEFAULT_RETRIES = 3\n\nfunction printHelp() {\n  console.log(`Translate unfinished xcstrings entries through Xcode's XLIFF flow.\n\nUsage:\n  npm run translate:xcstrings -- [options]\n\nOptions:\n  --project <file>        Xcode project path (default: ${DEFAULT_PROJECT_PATH})\n  --model <id>            OpenRouter model id (default: ${DEFAULT_MODEL})\n  --languages <list>      Comma-separated target languages to export\n  --batch-size <number>   Units per model request (default: ${DEFAULT_BATCH_SIZE})\n  --max-units <number>    Stop after N unfinished units\n  --base-url <url>        API base URL (default: ${DEFAULT_BASE_URL})\n  --dry-run               Export and inspect only, do not write back\n  --keep-export           Keep the temporary exported .xcloc bundle\n  --help                  Show this help\n\nEnvironment:\n  OPENROUTER_API_KEY      Required API key\n  OPENROUTER_MODEL        Default model override\n  OPENROUTER_BASE_URL     Default base URL override\n  OPENROUTER_SITE_URL     Optional HTTP-Referer header\n  OPENROUTER_APP_NAME     Optional X-Title header\n`)\n}\n\nfunction parseArgs(argv) {\n  const options = {\n    project: DEFAULT_PROJECT_PATH,\n    model: process.env.OPENROUTER_MODEL || DEFAULT_MODEL,\n    baseUrl: process.env.OPENROUTER_BASE_URL || DEFAULT_BASE_URL,\n    batchSize: DEFAULT_BATCH_SIZE,\n    maxUnits: null,\n    languages: [],\n    dryRun: false,\n    keepExport: false,\n    help: false,\n  }\n\n  for (let index = 0; index < argv.length; index += 1) {\n    const arg = argv[index]\n\n    if (arg === '--help') {\n      options.help = true\n      continue\n    }\n\n    if (arg === '--dry-run') {\n      options.dryRun = true\n      continue\n    }\n\n    if (arg === '--keep-export') {\n      options.keepExport = true\n      continue\n    }\n\n    if (!arg.startsWith('--')) {\n      throw new Error(`Unknown argument: ${arg}`)\n    }\n\n    const next = argv[index + 1]\n    if (next == null || next.startsWith('--')) {\n      throw new Error(`Missing value for ${arg}`)\n    }\n\n    switch (arg) {\n      case '--project':\n        options.project = next\n        break\n      case '--model':\n        options.model = next\n        break\n      case '--base-url':\n        options.baseUrl = next\n        break\n      case '--batch-size':\n        options.batchSize = parsePositiveInteger(next, '--batch-size')\n        break\n      case '--max-units':\n        options.maxUnits = parsePositiveInteger(next, '--max-units')\n        break\n      case '--languages':\n        options.languages = parseList(next)\n        break\n      default:\n        throw new Error(`Unknown argument: ${arg}`)\n    }\n\n    index += 1\n  }\n\n  return options\n}\n\nfunction parsePositiveInteger(value, flagName) {\n  const number = Number.parseInt(value, 10)\n  if (!Number.isInteger(number) || number <= 0) {\n    throw new Error(`${flagName} must be a positive integer`)\n  }\n  return number\n}\n\nfunction parseList(value) {\n  return value\n    .split(',')\n    .map(item => item.trim())\n    .filter(Boolean)\n}\n\nfunction isObject(value) {\n  return value != null && typeof value === 'object' && !Array.isArray(value)\n}\n\nasync function runCommand(command, args, options = {}) {\n  const { cwd = process.cwd() } = options\n\n  await new Promise((resolve, reject) => {\n    const child = spawn(command, args, {\n      cwd,\n      stdio: 'inherit',\n      env: process.env,\n    })\n\n    child.on('error', reject)\n    child.on('exit', code => {\n      if (code === 0) {\n        resolve()\n        return\n      }\n      reject(new Error(`${command} exited with code ${code}`))\n    })\n  })\n}\n\nfunction createClient(options) {\n  const apiKey = process.env.OPENROUTER_API_KEY\n  if (!apiKey) {\n    throw new Error('OPENROUTER_API_KEY is required')\n  }\n\n  const defaultHeaders = {}\n  if (process.env.OPENROUTER_SITE_URL) {\n    defaultHeaders['HTTP-Referer'] = process.env.OPENROUTER_SITE_URL\n  }\n  if (process.env.OPENROUTER_APP_NAME) {\n    defaultHeaders['X-Title'] = process.env.OPENROUTER_APP_NAME\n  }\n\n  return new OpenAI({\n    apiKey,\n    baseURL: options.baseUrl,\n    defaultHeaders,\n  })\n}\n\nasync function exportLocalizations(projectPath, exportPath, languages) {\n  const args = ['-exportLocalizations', '-project', projectPath, '-localizationPath', exportPath]\n  const exportLanguages = languages.length > 0 ? languages : await listProjectLanguages(projectPath)\n  for (const language of exportLanguages) {\n    args.push('-exportLanguage', language)\n  }\n\n  console.log('Exporting localizations with xcodebuild...')\n  await runCommand('xcodebuild', args)\n}\n\nasync function listProjectLanguages(projectPath) {\n  const pbxprojPath = path.join(projectPath, 'project.pbxproj')\n  const projectText = await fs.readFile(pbxprojPath, 'utf8')\n  const match = projectText.match(/knownRegions = \\(([^;]+)\\);/s)\n  if (!match) {\n    return []\n  }\n\n  return match[1]\n    .split(',')\n    .map(item => item.replace(/\\/\\*.*?\\*\\//g, '').replace(/[\"\\s]/g, ''))\n    .filter(language => language && language !== 'Base' && language !== 'en')\n}\n\nasync function importLocalizations(projectPath, xclocPaths) {\n  for (const xclocPath of xclocPaths) {\n    console.log(`Importing translated localizations from ${path.basename(xclocPath)}...`)\n    await runCommand('xcodebuild', [\n      '-importLocalizations',\n      '-project',\n      projectPath,\n      '-localizationPath',\n      xclocPath,\n      '-mergeImport',\n    ])\n  }\n}\n\nasync function findExportedXLIFFFiles(exportPath) {\n  const entries = await fs.readdir(exportPath, { withFileTypes: true })\n  const files = []\n\n  for (const entry of entries) {\n    if (!entry.isDirectory() || !entry.name.endsWith('.xcloc')) {\n      continue\n    }\n\n    const xclocPath = path.join(exportPath, entry.name)\n    const contentsPath = path.join(xclocPath, 'contents.json')\n    const contents = JSON.parse(await fs.readFile(contentsPath, 'utf8'))\n    const localizedDir = path.join(xclocPath, 'Localized Contents')\n    const localizedEntries = await fs.readdir(localizedDir, { withFileTypes: true })\n\n    for (const localizedEntry of localizedEntries) {\n      if (!localizedEntry.isFile() || !localizedEntry.name.endsWith('.xliff')) {\n        continue\n      }\n\n      files.push({\n        language: contents.targetLocale,\n        xclocPath,\n        xliffPath: path.join(localizedDir, localizedEntry.name),\n      })\n    }\n  }\n\n  return files.sort((left, right) => left.language.localeCompare(right.language, 'en'))\n}\n\nfunction getFirstChildByTagName(node, tagName) {\n  for (let child = node.firstChild; child != null; child = child.nextSibling) {\n    if (child.nodeType === child.ELEMENT_NODE && child.tagName === tagName) {\n      return child\n    }\n  }\n  return null\n}\n\nfunction shouldKeepUnchanged(source, id) {\n  const trimmed = source.trim()\n  if (!trimmed) {\n    return true\n  }\n\n  if (trimmed.includes('%#@')) {\n    return true\n  }\n\n  if (/^[\\d\\s.,%()+\\-–—:;<>/=\\\\[\\\\]{}]*$/.test(trimmed)) {\n    return true\n  }\n\n  if (/^[^\\p{L}]*$/u.test(trimmed)) {\n    return true\n  }\n\n  if (id === '') {\n    return true\n  }\n\n  return false\n}\n\nfunction filterDocumentToXCStrings(document) {\n  const files = Array.from(document.getElementsByTagName('file'))\n  for (const fileNode of files) {\n    const original = fileNode.getAttribute('original') || ''\n    if (original.endsWith('.xcstrings')) {\n      continue\n    }\n    fileNode.parentNode?.removeChild(fileNode)\n  }\n}\n\nfunction collectPendingUnits(document, language) {\n  const files = Array.from(document.getElementsByTagName('file'))\n  const units = []\n\n  for (const fileNode of files) {\n    const original = fileNode.getAttribute('original') || ''\n    if (!original.endsWith('.xcstrings')) {\n      continue\n    }\n\n    const transUnits = Array.from(fileNode.getElementsByTagName('trans-unit'))\n    for (const transUnit of transUnits) {\n      const id = transUnit.getAttribute('id') || ''\n      const sourceNode = getFirstChildByTagName(transUnit, 'source')\n      const targetNode = getFirstChildByTagName(transUnit, 'target')\n      const noteNode = getFirstChildByTagName(transUnit, 'note')\n      const source = sourceNode?.textContent || ''\n      const target = targetNode?.textContent || ''\n      const state = targetNode?.getAttribute('state') || ''\n\n      if (source.trim().length === 0) {\n        continue\n      }\n\n      if (state === 'translated' && target.length > 0) {\n        continue\n      }\n\n      units.push({\n        id,\n        language,\n        source,\n        note: noteNode?.textContent || '',\n        targetNode,\n        transUnit,\n      })\n    }\n  }\n\n  return units\n}\n\nfunction buildMessages(language, batch) {\n  const system = [\n    'You translate Apple XLIFF units for a macOS utility app.',\n    'Return JSON only. Do not wrap it in Markdown.',\n    'Use the provided note field as translator context whenever it is present.',\n    'PLACEHOLDERS are sacred. Preserve placeholders and special tokens exactly, including PLACEHOLDER, %@, %1$@, %2$@, %d, %lld, %.1f, %#@value@, %%, escaped newlines, escaped tabs, and surrounding punctuation.',\n    'ICU plural categories differ by locale: Chinese commonly uses other, English commonly uses one and other, and some locales also use zero, two, few, or many.',\n    'If an id refers to a plural or substitution branch such as .plural. or .substitutions., translate only that branch, do not invent or remove categories, and keep placeholder skeletons like %#@value@ unchanged.',\n    'Keep ids unchanged.',\n    'Use concise, natural product UI wording.',\n    'If a string should remain identical in the target language, return it unchanged.',\n    'Output format: {\"items\":[{\"id\":\"...\",\"target\":\"...\"}]}.',\n  ].join(' ')\n\n  const user = {\n    targetLanguage: language,\n    items: batch.map(item => ({\n      id: item.id,\n      source: item.source,\n      note: item.note,\n    })),\n  }\n\n  return [\n    { role: 'system', content: system },\n    { role: 'user', content: JSON.stringify(user) },\n  ]\n}\n\nfunction extractJson(text) {\n  const trimmed = text.trim()\n  if (!trimmed) {\n    throw new Error('Model returned an empty response')\n  }\n\n  try {\n    return JSON.parse(trimmed)\n  } catch {}\n\n  const fenced = trimmed.match(/```(?:json)?\\s*([\\s\\S]*?)```/i)\n  if (fenced) {\n    return JSON.parse(fenced[1])\n  }\n\n  const start = trimmed.indexOf('{')\n  const end = trimmed.lastIndexOf('}')\n  if (start >= 0 && end > start) {\n    return JSON.parse(trimmed.slice(start, end + 1))\n  }\n\n  throw new Error('Unable to parse JSON from model response')\n}\n\nfunction validateBatchResponse(batch, response) {\n  if (!isObject(response) || !Array.isArray(response.items)) {\n    throw new Error('Model response must include an items array')\n  }\n\n  const translatedById = new Map(response.items.map(item => [item.id, item]))\n  for (const item of batch) {\n    const translated = translatedById.get(item.id)\n    if (!translated || typeof translated.target !== 'string') {\n      throw new Error(`Missing translation for unit: ${item.id}`)\n    }\n  }\n\n  return translatedById\n}\n\nasync function translateBatch(client, language, batch, options, attempt = 1) {\n  try {\n    const completion = await client.chat.completions.create({\n      model: options.model,\n      temperature: 0.2,\n      messages: buildMessages(language, batch),\n    })\n\n    const content = completion.choices[0]?.message?.content || ''\n    const response = extractJson(content)\n    return validateBatchResponse(batch, response)\n  } catch (error) {\n    if (attempt >= DEFAULT_RETRIES) {\n      throw error\n    }\n\n    const delayMs = 1000 * 2 ** (attempt - 1)\n    console.warn(`Retrying ${language} batch after error: ${error.message}`)\n    await new Promise(resolve => setTimeout(resolve, delayMs))\n    return translateBatch(client, language, batch, options, attempt + 1)\n  }\n}\n\nfunction createTargetNode(document, transUnit) {\n  const targetNode = document.createElement('target')\n  const noteNode = getFirstChildByTagName(transUnit, 'note')\n\n  if (noteNode) {\n    transUnit.insertBefore(targetNode, noteNode)\n  } else {\n    transUnit.appendChild(targetNode)\n  }\n\n  return targetNode\n}\n\nfunction chunk(items, size) {\n  const chunks = []\n  for (let index = 0; index < items.length; index += size) {\n    chunks.push(items.slice(index, index + size))\n  }\n  return chunks\n}\n\nasync function processXLIFFFile(fileInfo, client, options, remainingBudget) {\n  const xml = await fs.readFile(fileInfo.xliffPath, 'utf8')\n  const document = new DOMParser().parseFromString(xml, 'application/xml')\n  filterDocumentToXCStrings(document)\n  let units = collectPendingUnits(document, fileInfo.language)\n\n  if (remainingBudget != null) {\n    units = units.slice(0, remainingBudget)\n  }\n\n  if (units.length === 0) {\n    return { language: fileInfo.language, translatedCount: 0, scannedCount: 0 }\n  }\n\n  console.log(`Found ${units.length} unfinished units for ${fileInfo.language}.`)\n\n  if (options.dryRun) {\n    return { language: fileInfo.language, translatedCount: 0, scannedCount: units.length }\n  }\n\n  let translatedCount = 0\n  const modelUnits = []\n\n  for (const unit of units) {\n    if (!shouldKeepUnchanged(unit.source, unit.id)) {\n      modelUnits.push(unit)\n      continue\n    }\n\n    const targetNode = unit.targetNode || createTargetNode(document, unit.transUnit)\n    targetNode.setAttribute('state', 'translated')\n    targetNode.textContent = unit.source\n    translatedCount += 1\n  }\n\n  const batches = chunk(modelUnits, options.batchSize)\n\n  for (const [index, batch] of batches.entries()) {\n    console.log(`Translating ${fileInfo.language} batch ${index + 1}/${batches.length}...`)\n    const translations = await translateBatch(client, fileInfo.language, batch, options)\n\n    for (const unit of batch) {\n      const translated = translations.get(unit.id)\n      const targetNode = unit.targetNode || createTargetNode(document, unit.transUnit)\n      targetNode.setAttribute('state', 'translated')\n      targetNode.textContent = translated.target\n      translatedCount += 1\n    }\n  }\n\n  const output = new XMLSerializer().serializeToString(document)\n  await fs.writeFile(fileInfo.xliffPath, `${output}\\n`)\n\n  return { language: fileInfo.language, translatedCount, scannedCount: units.length }\n}\n\nasync function removeDirectoryIfNeeded(targetPath, keep) {\n  if (keep) {\n    console.log(`Kept exported localizations at ${targetPath}`)\n    return\n  }\n\n  await fs.rm(targetPath, { recursive: true, force: true })\n}\n\nasync function main() {\n  const options = parseArgs(process.argv.slice(2))\n  if (options.help) {\n    printHelp()\n    return\n  }\n\n  const projectPath = path.resolve(process.cwd(), options.project)\n  const exportPath = await fs.mkdtemp(path.join(os.tmpdir(), 'linearmouse-xcloc-'))\n  const shouldKeepExport = options.keepExport || options.dryRun\n\n  try {\n    await exportLocalizations(projectPath, exportPath, options.languages)\n    const exportedFiles = await findExportedXLIFFFiles(exportPath)\n\n    if (exportedFiles.length === 0) {\n      console.log('No exported XLIFF files found.')\n      return\n    }\n\n    let remainingBudget = options.maxUnits\n    let totalPendingUnits = 0\n    let totalTranslatedUnits = 0\n    const perLanguage = []\n    const client = options.dryRun ? null : createClient(options)\n\n    for (const fileInfo of exportedFiles) {\n      if (remainingBudget === 0) {\n        break\n      }\n\n      const result = await processXLIFFFile(fileInfo, client, options, remainingBudget)\n      totalPendingUnits += result.scannedCount\n      totalTranslatedUnits += result.translatedCount\n      perLanguage.push(result)\n\n      if (remainingBudget != null) {\n        remainingBudget -= result.scannedCount\n      }\n    }\n\n    if (totalPendingUnits === 0) {\n      console.log('No unfinished xcstrings translations found.')\n      return\n    }\n\n    for (const result of perLanguage) {\n      if (result.scannedCount === 0) {\n        continue\n      }\n\n      if (options.dryRun) {\n        console.log(`${result.language}: ${result.scannedCount} unfinished units`)\n      } else {\n        console.log(`${result.language}: translated ${result.translatedCount} units`)\n      }\n    }\n\n    if (options.dryRun) {\n      console.log(`Dry run complete. Found ${totalPendingUnits} unfinished units.`)\n      return\n    }\n\n    if (totalTranslatedUnits === 0) {\n      console.log('Nothing was translated.')\n      return\n    }\n\n    const xclocPaths = [...new Set(exportedFiles.map(file => file.xclocPath))]\n    await importLocalizations(projectPath, xclocPaths)\n    console.log(`Imported ${totalTranslatedUnits} translated units into the project.`)\n  } finally {\n    await removeDirectoryIfNeeded(exportPath, shouldKeepExport)\n  }\n}\n\nmain().catch(error => {\n  console.error(error.message)\n  process.exitCode = 1\n})\n"
  },
  {
    "path": "Signing.xcconfig.tpl",
    "content": "CODE_SIGN_STYLE = Manual\nDEVELOPMENT_TEAM =\n"
  },
  {
    "path": "crowdin.yml",
    "content": "pull_request_title: Update translations\ncommit_message: Update translations (%language%)\nappend_commit_message: \nfiles:\n  - source: /LinearMouse/Localizable.xcstrings\n    translation: /LinearMouse/Localizable.xcstrings\n    multilingual: 1\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"linearmouse\",\n  \"private\": true,\n  \"scripts\": {\n    \"generate:json-schema\": \"ts-json-schema-generator --path 'Documentation/Configuration.d.ts' --type Configuration > Documentation/Configuration.json\",\n    \"translate:xcstrings\": \"node Scripts/translate-xcstrings.mjs\"\n  },\n  \"dependencies\": {\n    \"@xmldom/xmldom\": \"^0.8.10\",\n    \"openai\": \"^4.104.0\"\n  },\n  \"overrides\": {\n    \"@types/node\": \"18.11.18\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"18.11.18\",\n    \"ts-json-schema-generator\": \"^1.0.0\"\n  }\n}\n"
  }
]